PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
gin_private.h File Reference
#include "access/amapi.h"
#include "access/gin.h"
#include "access/ginblock.h"
#include "access/itup.h"
#include "common/int.h"
#include "catalog/pg_am_d.h"
#include "fmgr.h"
#include "lib/rbtree.h"
#include "storage/bufmgr.h"
Include dependency graph for gin_private.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  GinOptions
 
struct  GinState
 
struct  GinBtreeStack
 
struct  GinBtreeData
 
struct  GinBtreeEntryInsertData
 
struct  GinBtreeDataLeafInsertData
 
struct  GinScanKeyData
 
struct  GinScanEntryData
 
struct  GinScanOpaqueData
 
struct  GinEntryAccumulator
 
struct  BuildAccumulator
 
struct  GinTupleCollector
 

Macros

#define GIN_DEFAULT_USE_FASTUPDATE   true
 
#define GinGetUseFastUpdate(relation)
 
#define GinGetPendingListCleanupSize(relation)
 
#define GIN_UNLOCK   BUFFER_LOCK_UNLOCK
 
#define GIN_SHARE   BUFFER_LOCK_SHARE
 
#define GIN_EXCLUSIVE   BUFFER_LOCK_EXCLUSIVE
 

Typedefs

typedef struct GinOptions GinOptions
 
typedef struct GinState GinState
 
typedef struct GinBtreeStack GinBtreeStack
 
typedef struct GinBtreeDataGinBtree
 
typedef struct GinBtreeData GinBtreeData
 
typedef struct GinVacuumState GinVacuumState
 
typedef struct GinScanKeyDataGinScanKey
 
typedef struct GinScanEntryDataGinScanEntry
 
typedef struct GinScanKeyData GinScanKeyData
 
typedef struct GinScanEntryData GinScanEntryData
 
typedef struct GinScanOpaqueData GinScanOpaqueData
 
typedef GinScanOpaqueDataGinScanOpaque
 
typedef struct GinEntryAccumulator GinEntryAccumulator
 
typedef struct GinTupleCollector GinTupleCollector
 

Enumerations

enum  GinPlaceToPageRC { GPTP_NO_WORK , GPTP_INSERT , GPTP_SPLIT }
 

Functions

byteaginoptions (Datum reloptions, bool validate)
 
void initGinState (GinState *state, Relation index)
 
Buffer GinNewBuffer (Relation index)
 
void GinInitBuffer (Buffer b, uint32 f)
 
void GinInitPage (Page page, uint32 f, Size pageSize)
 
void GinInitMetabuffer (Buffer b)
 
int ginCompareEntries (GinState *ginstate, OffsetNumber attnum, Datum a, GinNullCategory categorya, Datum b, GinNullCategory categoryb)
 
int ginCompareAttEntries (GinState *ginstate, OffsetNumber attnuma, Datum a, GinNullCategory categorya, OffsetNumber attnumb, Datum b, GinNullCategory categoryb)
 
DatumginExtractEntries (GinState *ginstate, OffsetNumber attnum, Datum value, bool isNull, int32 *nentries, GinNullCategory **categories)
 
OffsetNumber gintuple_get_attrnum (GinState *ginstate, IndexTuple tuple)
 
Datum gintuple_get_key (GinState *ginstate, IndexTuple tuple, GinNullCategory *category)
 
char * ginbuildphasename (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 ItemPointer ipd, int nipd, int maxsize, int *nwritten)
 
int ginPostingListDecodeAllSegmentsToTbm (GinPostingList *ptr, int len, TIDBitmap *tbm)
 
ItemPointer ginPostingListDecodeAllSegments (GinPostingList *segment, int len, int *ndecoded_out)
 
ItemPointer ginPostingListDecode (GinPostingList *plist, int *ndecoded_out)
 
ItemPointer ginMergeItemPointers (ItemPointerData *a, uint32 na, ItemPointerData *b, uint32 nb, int *nmerged)
 
static int ginCompareItemPointers (ItemPointer a, ItemPointer b)
 
int ginTraverseLock (Buffer buffer, bool searchMode)
 

Macro Definition Documentation

◆ GIN_DEFAULT_USE_FASTUPDATE

#define GIN_DEFAULT_USE_FASTUPDATE   true

Definition at line 33 of file gin_private.h.

◆ GIN_EXCLUSIVE

#define GIN_EXCLUSIVE   BUFFER_LOCK_EXCLUSIVE

Definition at line 51 of file gin_private.h.

◆ GIN_SHARE

#define GIN_SHARE   BUFFER_LOCK_SHARE

Definition at line 50 of file gin_private.h.

◆ GIN_UNLOCK

#define GIN_UNLOCK   BUFFER_LOCK_UNLOCK

Definition at line 49 of file gin_private.h.

◆ GinGetPendingListCleanupSize

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

Definition at line 39 of file gin_private.h.

◆ GinGetUseFastUpdate

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

Definition at line 34 of file gin_private.h.

Typedef Documentation

◆ GinBtree

typedef struct GinBtreeData* GinBtree

Definition at line 141 of file gin_private.h.

◆ GinBtreeData

typedef struct GinBtreeData GinBtreeData

◆ GinBtreeStack

typedef struct GinBtreeStack GinBtreeStack

◆ GinEntryAccumulator

◆ GinOptions

typedef struct GinOptions GinOptions

◆ GinScanEntry

typedef struct GinScanEntryData* GinScanEntry

Definition at line 267 of file gin_private.h.

◆ GinScanEntryData

◆ GinScanKey

typedef struct GinScanKeyData* GinScanKey

Definition at line 265 of file gin_private.h.

◆ GinScanKeyData

◆ GinScanOpaque

Definition at line 394 of file gin_private.h.

◆ GinScanOpaqueData

◆ GinState

typedef struct GinState GinState

◆ GinTupleCollector

◆ GinVacuumState

Definition at line 243 of file gin_private.h.

Enumeration Type Documentation

◆ GinPlaceToPageRC

Enumerator
GPTP_NO_WORK 
GPTP_INSERT 
GPTP_SPLIT 

Definition at line 144 of file gin_private.h.

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

Function Documentation

◆ createPostingTree()

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

Definition at line 1775 of file gindatapage.c.

1777{
1778 BlockNumber blkno;
1779 Buffer buffer;
1780 Page tmppage;
1781 Page page;
1782 Pointer ptr;
1783 int nrootitems;
1784 int rootsize;
1785 bool is_build = (buildStats != NULL);
1786
1787 /* Construct the new root page in memory first. */
1788 tmppage = (Page) palloc(BLCKSZ);
1789 GinInitPage(tmppage, GIN_DATA | GIN_LEAF | GIN_COMPRESSED, BLCKSZ);
1790 GinPageGetOpaque(tmppage)->rightlink = InvalidBlockNumber;
1791
1792 /*
1793 * Write as many of the items to the root page as fit. In segments of max
1794 * GinPostingListSegmentMaxSize bytes each.
1795 */
1796 nrootitems = 0;
1797 rootsize = 0;
1798 ptr = (Pointer) GinDataLeafPageGetPostingList(tmppage);
1799 while (nrootitems < nitems)
1800 {
1801 GinPostingList *segment;
1802 int npacked;
1803 int segsize;
1804
1805 segment = ginCompressPostingList(&items[nrootitems],
1806 nitems - nrootitems,
1808 &npacked);
1809 segsize = SizeOfGinPostingList(segment);
1810 if (rootsize + segsize > GinDataPageMaxDataSize)
1811 break;
1812
1813 memcpy(ptr, segment, segsize);
1814 ptr += segsize;
1815 rootsize += segsize;
1816 nrootitems += npacked;
1817 pfree(segment);
1818 }
1819 GinDataPageSetDataSize(tmppage, rootsize);
1820
1821 /*
1822 * All set. Get a new physical page, and copy the in-memory page to it.
1823 */
1824 buffer = GinNewBuffer(index);
1825 page = BufferGetPage(buffer);
1826 blkno = BufferGetBlockNumber(buffer);
1827
1828 /*
1829 * Copy any predicate locks from the entry tree leaf (containing posting
1830 * list) to the posting tree.
1831 */
1833
1835
1836 PageRestoreTempPage(tmppage, page);
1837 MarkBufferDirty(buffer);
1838
1839 if (RelationNeedsWAL(index) && !is_build)
1840 {
1841 XLogRecPtr recptr;
1843
1844 data.size = rootsize;
1845
1848
1850 rootsize);
1852
1853 recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_CREATE_PTREE);
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,
1874 nitems - nrootitems,
1875 buildStats);
1876 }
1877
1878 return blkno;
1879}
uint32 BlockNumber
Definition: block.h:31
#define InvalidBlockNumber
Definition: block.h:33
int Buffer
Definition: buf.h:23
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:4231
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:5390
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:2952
static Page BufferGetPage(Buffer buffer)
Definition: bufmgr.h:417
void PageRestoreTempPage(Page tempPage, Page oldPage)
Definition: bufpage.c:423
static void PageSetLSN(Page page, XLogRecPtr lsn)
Definition: bufpage.h:391
PageData * Page
Definition: bufpage.h:82
char * Pointer
Definition: c.h:493
#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)
Definition: gindatapage.c:1908
GinPostingList * ginCompressPostingList(const ItemPointer ipd, int nipd, int maxsize, int *nwritten)
void GinInitPage(Page page, uint32 f, Size pageSize)
Definition: ginutil.c:343
Buffer GinNewBuffer(Relation index)
Definition: ginutil.c:305
#define XLOG_GIN_CREATE_PTREE
Definition: ginxlog.h:19
#define nitems(x)
Definition: indent.h:31
void pfree(void *pointer)
Definition: mcxt.c:2146
void * palloc(Size size)
Definition: mcxt.c:1939
#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:3144
#define RelationNeedsWAL(relation)
Definition: rel.h:639
BlockNumber nDataPages
Definition: gin.h:60
Definition: type.h:96
static ItemArray items
Definition: test_tidstore.c:48
uint64 XLogRecPtr
Definition: xlogdefs.h:21
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:474
void XLogRegisterData(const void *data, uint32 len)
Definition: xloginsert.c:364
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:242
void XLogBeginInsert(void)
Definition: xloginsert.c:149
#define REGBUF_WILL_INIT
Definition: xloginsert.h:34

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

Referenced by addItemPointersToLeafTuple(), and buildFreshLeafTuple().

◆ freeGinBtreeStack()

void freeGinBtreeStack ( GinBtreeStack stack)

Definition at line 198 of file ginbtree.c.

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

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

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

◆ ginadjustmembers()

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

Definition at line 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:
322 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
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:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
#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:96
bool ref_is_family
Definition: amapi.h:95
int number
Definition: amapi.h:90
bool ref_is_hard
Definition: amapi.h:94

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

Referenced by ginhandler().

◆ ginBeginBAScan()

void ginBeginBAScan ( BuildAccumulator accum)

Definition at line 257 of file ginbulk.c.

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

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 
)

Definition at line 25 of file ginscan.c.

26{
27 IndexScanDesc scan;
29
30 /* no order by operators allowed */
31 Assert(norderbys == 0);
32
33 scan = RelationGetIndexScan(rel, nkeys, norderbys);
34
35 /* allocate private workspace */
37 so->keys = NULL;
38 so->nkeys = 0;
40 "Gin scan temporary context",
43 "Gin scan key context",
46
47 scan->opaque = so;
48
49 return scan;
50}
IndexScanDesc RelationGetIndexScan(Relation indexRelation, int nkeys, int norderbys)
Definition: genam.c:80
GinScanOpaqueData * GinScanOpaque
Definition: gin_private.h:394
void initGinState(GinState *state, Relation index)
Definition: ginutil.c:102
Assert(PointerIsAligned(start, uint64))
MemoryContext CurrentMemoryContext
Definition: mcxt.c:159
#define AllocSetContextCreate
Definition: memutils.h:149
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:180
GinScanKey keys
Definition: gin_private.h:382
MemoryContext keyCtx
Definition: gin_private.h:389
MemoryContext tempCtx
Definition: gin_private.h:379
Relation indexRelation
Definition: relscan.h:137

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert(), CurrentMemoryContext, GinScanOpaqueData::ginstate, IndexScanDescData::indexRelation, initGinState(), GinScanOpaqueData::keyCtx, GinScanOpaqueData::keys, GinScanOpaqueData::nkeys, IndexScanDescData::opaque, palloc(), RelationGetIndexScan(), and GinScanOpaqueData::tempCtx.

Referenced by ginhandler().

◆ ginbuild()

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

Definition at line 581 of file gininsert.c.

582{
583 IndexBuildResult *result;
584 double reltuples;
585 GinBuildState buildstate;
586 GinBuildState *state = &buildstate;
587 Buffer RootBuffer,
588 MetaBuffer;
590 Datum key;
591 GinNullCategory category;
592 uint32 nlist;
593 MemoryContext oldCtx;
595
597 elog(ERROR, "index \"%s\" already contains data",
599
600 initGinState(&buildstate.ginstate, index);
601 buildstate.indtuples = 0;
602 memset(&buildstate.buildStats, 0, sizeof(GinStatsData));
603
604 /* Initialize fields for parallel build too. */
605 buildstate.bs_numtuples = 0;
606 buildstate.bs_reltuples = 0;
607 buildstate.bs_leader = NULL;
608 memset(&buildstate.tid, 0, sizeof(ItemPointerData));
609
610 /* initialize the meta page */
611 MetaBuffer = GinNewBuffer(index);
612
613 /* initialize the root page */
614 RootBuffer = GinNewBuffer(index);
615
617 GinInitMetabuffer(MetaBuffer);
618 MarkBufferDirty(MetaBuffer);
619 GinInitBuffer(RootBuffer, GIN_LEAF);
620 MarkBufferDirty(RootBuffer);
621
622
623 UnlockReleaseBuffer(MetaBuffer);
624 UnlockReleaseBuffer(RootBuffer);
626
627 /* count the root as first entry page */
628 buildstate.buildStats.nEntryPages++;
629
630 /*
631 * create a temporary memory context that is used to hold data not yet
632 * dumped out to the index
633 */
635 "Gin build temporary context",
637
638 /*
639 * create a temporary memory context that is used for calling
640 * ginExtractEntries(), and can be reset after each tuple
641 */
643 "Gin build temporary context for user-defined function",
645
646 buildstate.accum.ginstate = &buildstate.ginstate;
647 ginInitBA(&buildstate.accum);
648
649 /* Report table scan phase started */
652
653 /*
654 * Attempt to launch parallel worker scan when required
655 *
656 * XXX plan_create_index_workers makes the number of workers dependent on
657 * maintenance_work_mem, requiring 32MB for each worker. For GIN that's
658 * reasonable too, because we sort the data just like btree. It does
659 * ignore the memory used to accumulate data in memory (set by work_mem),
660 * but there is no way to communicate that to plan_create_index_workers.
661 */
662 if (indexInfo->ii_ParallelWorkers > 0)
663 _gin_begin_parallel(state, heap, index, indexInfo->ii_Concurrent,
664 indexInfo->ii_ParallelWorkers);
665
666 /*
667 * If parallel build requested and at least one worker process was
668 * successfully launched, set up coordination state, wait for workers to
669 * complete. Then read all tuples from the shared tuplesort and insert
670 * them into the index.
671 *
672 * In serial mode, simply scan the table and build the index one index
673 * tuple at a time.
674 */
675 if (state->bs_leader)
676 {
677 SortCoordinate coordinate;
678
679 coordinate = (SortCoordinate) palloc0(sizeof(SortCoordinateData));
680 coordinate->isWorker = false;
681 coordinate->nParticipants =
682 state->bs_leader->nparticipanttuplesorts;
683 coordinate->sharedsort = state->bs_leader->sharedsort;
684
685 /*
686 * Begin leader tuplesort.
687 *
688 * In cases where parallelism is involved, the leader receives the
689 * same share of maintenance_work_mem as a serial sort (it is
690 * generally treated in the same way as a serial sort once we return).
691 * Parallel worker Tuplesortstates will have received only a fraction
692 * of maintenance_work_mem, though.
693 *
694 * We rely on the lifetime of the Leader Tuplesortstate almost not
695 * overlapping with any worker Tuplesortstate's lifetime. There may
696 * be some small overlap, but that's okay because we rely on leader
697 * Tuplesortstate only allocating a small, fixed amount of memory
698 * here. When its tuplesort_performsort() is called (by our caller),
699 * and significant amounts of memory are likely to be used, all
700 * workers must have already freed almost all memory held by their
701 * Tuplesortstates (they are about to go away completely, too). The
702 * overall effect is that maintenance_work_mem always represents an
703 * absolute high watermark on the amount of memory used by a CREATE
704 * INDEX operation, regardless of the use of parallelism or any other
705 * factor.
706 */
707 state->bs_sortstate =
709 maintenance_work_mem, coordinate,
711
712 /* scan the relation in parallel and merge per-worker results */
713 reltuples = _gin_parallel_merge(state);
714
715 _gin_end_parallel(state->bs_leader, state);
716 }
717 else /* no parallel index build */
718 {
719 /*
720 * Do the heap scan. We disallow sync scan here because
721 * dataPlaceToPage prefers to receive tuples in TID order.
722 */
723 reltuples = table_index_build_scan(heap, index, indexInfo, false, true,
724 ginBuildCallback, &buildstate, NULL);
725
726 /* dump remaining entries to the index */
727 oldCtx = MemoryContextSwitchTo(buildstate.tmpCtx);
728 ginBeginBAScan(&buildstate.accum);
729 while ((list = ginGetBAEntry(&buildstate.accum,
730 &attnum, &key, &category, &nlist)) != NULL)
731 {
732 /* there could be many entries, so be willing to abort here */
734 ginEntryInsert(&buildstate.ginstate, attnum, key, category,
735 list, nlist, &buildstate.buildStats);
736 }
737 MemoryContextSwitchTo(oldCtx);
738 }
739
740 MemoryContextDelete(buildstate.funcCtx);
741 MemoryContextDelete(buildstate.tmpCtx);
742
743 /*
744 * Update metapage stats
745 */
747 ginUpdateStats(index, &buildstate.buildStats, true);
748
749 /*
750 * We didn't write WAL records as we built the index, so if WAL-logging is
751 * required, write all pages to the WAL now.
752 */
754 {
757 true);
758 }
759
760 /*
761 * Return statistics
762 */
763 result = (IndexBuildResult *) palloc(sizeof(IndexBuildResult));
764
765 result->heap_tuples = reltuples;
766 result->index_tuples = buildstate.indtuples;
767
768 return result;
769}
void pgstat_progress_update_param(int index, int64 val)
#define RelationGetNumberOfBlocks(reln)
Definition: bufmgr.h:283
uint32_t uint32
Definition: c.h:502
#define PROGRESS_GIN_PHASE_INDEXBUILD_TABLESCAN
Definition: gin.h:46
signed char GinNullCategory
Definition: ginblock.h:206
void ginBeginBAScan(BuildAccumulator *accum)
Definition: ginbulk.c:257
ItemPointerData * ginGetBAEntry(BuildAccumulator *accum, OffsetNumber *attnum, Datum *key, GinNullCategory *category, uint32 *n)
Definition: ginbulk.c:268
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:339
static void _gin_end_parallel(GinLeader *ginleader, GinBuildState *state)
Definition: gininsert.c:1075
static void _gin_begin_parallel(GinBuildState *buildstate, Relation heap, Relation index, bool isconcurrent, int request)
Definition: gininsert.c:896
static double _gin_parallel_merge(GinBuildState *state)
Definition: gininsert.c:1613
static void ginBuildCallback(Relation index, ItemPointer tid, Datum *values, bool *isnull, bool tupleIsAlive, void *state)
Definition: gininsert.c:440
void GinInitBuffer(Buffer b, uint32 f)
Definition: ginutil.c:355
void GinInitMetabuffer(Buffer b)
Definition: ginutil.c:361
void ginUpdateStats(Relation index, const GinStatsData *stats, bool is_build)
Definition: ginutil.c:655
int maintenance_work_mem
Definition: globals.c:134
void * palloc0(Size size)
Definition: mcxt.c:1969
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:485
#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
Definition: pg_attribute.h:74
uintptr_t Datum
Definition: postgres.h:69
#define PROGRESS_CREATEIDX_SUBPHASE
Definition: progress.h:88
#define RelationGetRelationName(relation)
Definition: rel.h:550
@ MAIN_FORKNUM
Definition: relpath.h:58
GinState * ginstate
Definition: gin_private.h:441
double indtuples
Definition: gininsert.c:142
GinState ginstate
Definition: gininsert.c:141
double bs_reltuples
Definition: gininsert.c:159
MemoryContext tmpCtx
Definition: gininsert.c:144
GinLeader * bs_leader
Definition: gininsert.c:154
GinStatsData buildStats
Definition: gininsert.c:143
ItemPointerData tid
Definition: gininsert.c:147
double bs_numtuples
Definition: gininsert.c:158
MemoryContext funcCtx
Definition: gininsert.c:145
BuildAccumulator accum
Definition: gininsert.c:146
BlockNumber nEntryPages
Definition: gin.h:59
BlockNumber nTotalPages
Definition: gin.h:58
double heap_tuples
Definition: genam.h:55
double index_tuples
Definition: genam.h:56
int ii_ParallelWorkers
Definition: execnodes.h:218
bool ii_Concurrent
Definition: execnodes.h:214
Sharedsort * sharedsort
Definition: tuplesort.h:59
Definition: regguts.h:323
static double table_index_build_scan(Relation table_rel, Relation index_rel, struct IndexInfo *index_info, bool allow_sync, bool progress, IndexBuildCallback callback, void *callback_state, TableScanDesc scan)
Definition: tableam.h:1735
struct SortCoordinateData * SortCoordinate
Definition: tuplesort.h:62
#define TUPLESORT_NONE
Definition: tuplesort.h:94
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)
Definition: xloginsert.c:1270

References _gin_begin_parallel(), _gin_end_parallel(), _gin_parallel_merge(), GinBuildState::accum, ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, attnum, GinBuildState::bs_leader, GinBuildState::bs_numtuples, GinBuildState::bs_reltuples, GinBuildState::buildStats, CHECK_FOR_INTERRUPTS, CurrentMemoryContext, elog, END_CRIT_SECTION, ERROR, GinBuildState::funcCtx, GIN_LEAF, ginBeginBAScan(), ginBuildCallback(), ginEntryInsert(), ginGetBAEntry(), ginInitBA(), GinInitBuffer(), GinInitMetabuffer(), GinNewBuffer(), GinBuildState::ginstate, BuildAccumulator::ginstate, ginUpdateStats(), IndexBuildResult::heap_tuples, IndexInfo::ii_Concurrent, IndexInfo::ii_ParallelWorkers, IndexBuildResult::index_tuples, GinBuildState::indtuples, initGinState(), SortCoordinateData::isWorker, sort-test::key, sort-test::list, log_newpage_range(), MAIN_FORKNUM, maintenance_work_mem, MarkBufferDirty(), MemoryContextDelete(), MemoryContextSwitchTo(), GinStatsData::nEntryPages, SortCoordinateData::nParticipants, GinStatsData::nTotalPages, palloc(), palloc0(), pgstat_progress_update_param(), PROGRESS_CREATEIDX_SUBPHASE, PROGRESS_GIN_PHASE_INDEXBUILD_TABLESCAN, RelationGetNumberOfBlocks, RelationGetRelationName, RelationNeedsWAL, SortCoordinateData::sharedsort, START_CRIT_SECTION, table_index_build_scan(), GinBuildState::tid, GinBuildState::tmpCtx, tuplesort_begin_index_gin(), TUPLESORT_NONE, and UnlockReleaseBuffer().

Referenced by ginhandler().

◆ ginbuildempty()

void ginbuildempty ( Relation  index)

Definition at line 775 of file gininsert.c.

776{
777 Buffer RootBuffer,
778 MetaBuffer;
779
780 /* An empty GIN index has two pages. */
781 MetaBuffer = ExtendBufferedRel(BMR_REL(index), INIT_FORKNUM, NULL,
783 RootBuffer = ExtendBufferedRel(BMR_REL(index), INIT_FORKNUM, NULL,
785
786 /* Initialize and xlog metabuffer and root buffer. */
788 GinInitMetabuffer(MetaBuffer);
789 MarkBufferDirty(MetaBuffer);
790 log_newpage_buffer(MetaBuffer, true);
791 GinInitBuffer(RootBuffer, GIN_LEAF);
792 MarkBufferDirty(RootBuffer);
793 log_newpage_buffer(RootBuffer, false);
795
796 /* Unlock and release the buffers. */
797 UnlockReleaseBuffer(MetaBuffer);
798 UnlockReleaseBuffer(RootBuffer);
799}
Buffer ExtendBufferedRel(BufferManagerRelation bmr, ForkNumber forkNum, BufferAccessStrategy strategy, uint32 flags)
Definition: bufmgr.c:858
@ EB_SKIP_EXTENSION_LOCK
Definition: bufmgr.h:75
@ EB_LOCK_FIRST
Definition: bufmgr.h:87
#define BMR_REL(p_rel)
Definition: bufmgr.h:108
@ INIT_FORKNUM
Definition: relpath.h:61
XLogRecPtr log_newpage_buffer(Buffer buffer, bool page_std)
Definition: xloginsert.c:1237

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

Referenced by ginhandler().

◆ ginbuildphasename()

char * ginbuildphasename ( int64  phasenum)

Definition at line 712 of file ginutil.c.

713{
714 switch (phasenum)
715 {
717 return "initializing";
719 return "scanning table";
721 return "sorting tuples (workers)";
723 return "merging tuples (workers)";
725 return "sorting tuples";
727 return "merging tuples";
728 default:
729 return NULL;
730 }
731}
#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:109

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

Definition at line 564 of file ginvacuum.c.

566{
567 Relation index = info->index;
569 GinVacuumState gvs;
570 Buffer buffer;
571 BlockNumber rootOfPostingTree[BLCKSZ / (sizeof(IndexTupleData) + sizeof(ItemId))];
572 uint32 nRoot;
573
575 "Gin vacuum temporary context",
577 gvs.index = index;
578 gvs.callback = callback;
579 gvs.callback_state = callback_state;
580 gvs.strategy = info->strategy;
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);
642 Page resPage;
643 uint32 i;
644
645 Assert(!GinPageIsData(page));
646
647 resPage = ginVacuumEntryPage(&gvs, buffer, rootOfPostingTree, &nRoot);
648
649 blkno = GinPageGetOpaque(page)->rightlink;
650
651 if (resPage)
652 {
654 PageRestoreTempPage(resPage, page);
655 MarkBufferDirty(buffer);
656 xlogVacuumPage(gvs.index, buffer);
657 UnlockReleaseBuffer(buffer);
659 }
660 else
661 {
662 UnlockReleaseBuffer(buffer);
663 }
664
665 vacuum_delay_point(false);
666
667 for (i = 0; i < nRoot; i++)
668 {
669 ginVacuumPostingTree(&gvs, rootOfPostingTree[i]);
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
682
683 return gvs.result;
684}
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:5607
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition: bufmgr.c:805
@ RBM_NORMAL
Definition: bufmgr.h:46
static Item PageGetItem(const PageData *page, const ItemIdData *itemId)
Definition: bufpage.h:354
static ItemId PageGetItemId(Page page, OffsetNumber offsetNumber)
Definition: bufpage.h:244
static OffsetNumber PageGetMaxOffsetNumber(const PageData *page)
Definition: bufpage.h:372
#define GIN_UNLOCK
Definition: gin_private.h:49
#define GIN_EXCLUSIVE
Definition: gin_private.h:51
#define GIN_SHARE
Definition: gin_private.h:50
#define GIN_ROOT_BLKNO
Definition: ginblock.h:52
#define GinGetDownlink(itup)
Definition: ginblock.h:257
#define GinPageIsData(page)
Definition: ginblock.h:115
#define GinPageIsLeaf(page)
Definition: ginblock.h:112
void ginInsertCleanup(GinState *ginstate, bool full_clean, bool fill_fsm, bool forceCleanup, IndexBulkDeleteResult *stats)
Definition: ginfast.c:780
static void xlogVacuumPage(Relation index, Buffer buffer)
Definition: ginvacuum.c:89
static void ginVacuumPostingTree(GinVacuumState *gvs, BlockNumber rootBlkno)
Definition: ginvacuum.c:408
static Page ginVacuumEntryPage(GinVacuumState *gvs, Buffer buffer, BlockNumber *roots, uint32 *nroot)
Definition: ginvacuum.c:455
int i
Definition: isn.c:77
IndexTupleData * IndexTuple
Definition: itup.h:53
struct IndexTupleData IndexTupleData
#define AmAutoVacuumWorkerProcess()
Definition: miscadmin.h:383
#define FirstOffsetNumber
Definition: off.h:27
MemoryContext tmpCxt
Definition: ginvacuum.c:35
BufferAccessStrategy strategy
Definition: ginvacuum.c:34
IndexBulkDeleteCallback callback
Definition: ginvacuum.c:31
IndexBulkDeleteResult * result
Definition: ginvacuum.c:30
void * callback_state
Definition: ginvacuum.c:32
GinState ginstate
Definition: ginvacuum.c:33
Relation index
Definition: ginvacuum.c:29
double num_index_tuples
Definition: genam.h:102
Relation index
Definition: genam.h:69
BufferAccessStrategy strategy
Definition: genam.h:76
static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)
Definition: test_ifaddrs.c:46
void vacuum_delay_point(bool is_analyze)
Definition: vacuum.c:2404

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

Referenced by ginhandler().

◆ ginCompareAttEntries()

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

Definition at line 415 of file ginutil.c.

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

References a, b, and ginCompareEntries().

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

◆ ginCompareEntries()

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

Definition at line 393 of file ginutil.c.

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

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

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

◆ ginCompareItemPointers()

static int ginCompareItemPointers ( ItemPointer  a,
ItemPointer  b 
)
inlinestatic

◆ ginCompressPostingList()

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

Definition at line 197 of file ginpostinglist.c.

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

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

Referenced by _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 
)

Definition at line 1349 of file gindatapage.c.

1350{
1351 PostingItem li,
1352 ri;
1353
1354 li.key = *GinDataPageGetRightBound(lpage);
1355 PostingItemSetBlockNumber(&li, lblkno);
1357
1358 ri.key = *GinDataPageGetRightBound(rpage);
1359 PostingItemSetBlockNumber(&ri, rblkno);
1361}
#define GinDataPageGetRightBound(page)
Definition: ginblock.h:288
#define PostingItemSetBlockNumber(pointer, blockNumber)
Definition: ginblock.h:192
void GinDataPageAddPostingItem(Page page, PostingItem *data, OffsetNumber offset)
Definition: gindatapage.c:380
#define InvalidOffsetNumber
Definition: off.h:26
tree ctl root
Definition: radixtree.h:1857
ItemPointerData key
Definition: ginblock.h:186

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

Referenced by ginPrepareDataScan().

◆ GinDataLeafPageGetItems()

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

Definition at line 135 of file gindatapage.c.

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

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

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

◆ GinDataLeafPageGetItemsToTbm()

int GinDataLeafPageGetItemsToTbm ( Page  page,
TIDBitmap tbm 
)

Definition at line 182 of file gindatapage.c.

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

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

Referenced by scanPostingTree().

◆ GinDataPageAddPostingItem()

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

Definition at line 380 of file gindatapage.c.

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

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

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

◆ ginendscan()

void ginendscan ( IndexScanDesc  scan)

Definition at line 463 of file ginscan.c.

464{
466
467 ginFreeScanKeys(so);
468
471
472 pfree(so);
473}
void ginFreeScanKeys(GinScanOpaque so)
Definition: ginscan.c:239

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

Referenced by ginhandler().

◆ ginEntryFillRoot()

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

Definition at line 723 of file ginentrypage.c.

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

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

Referenced by ginPrepareEntryScan().

◆ ginEntryInsert()

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

Definition at line 339 of file gininsert.c.

343{
344 GinBtreeData btree;
345 GinBtreeEntryInsertData insertdata;
346 GinBtreeStack *stack;
347 IndexTuple itup;
348 Page page;
349
350 insertdata.isDelete = false;
351
352 ginPrepareEntryScan(&btree, attnum, key, category, ginstate);
353 btree.isBuild = (buildStats != NULL);
354
355 stack = ginFindLeafPage(&btree, false, false);
356 page = BufferGetPage(stack->buffer);
357
358 if (btree.findItem(&btree, stack))
359 {
360 /* found pre-existing entry */
361 itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, stack->off));
362
363 if (GinIsPostingTree(itup))
364 {
365 /* add entries to existing posting tree */
366 BlockNumber rootPostingTree = GinGetPostingTree(itup);
367
368 /* release all stack */
370 freeGinBtreeStack(stack);
371
372 /* insert into posting tree */
373 ginInsertItemPointers(ginstate->index, rootPostingTree,
374 items, nitem,
375 buildStats);
376 return;
377 }
378
381 /* modify an existing leaf entry */
382 itup = addItemPointersToLeafTuple(ginstate, itup,
383 items, nitem, buildStats, stack->buffer);
384
385 insertdata.isDelete = true;
386 }
387 else
388 {
391 /* no match, so construct a new leaf entry */
392 itup = buildFreshLeafTuple(ginstate, attnum, key, category,
393 items, nitem, buildStats, stack->buffer);
394
395 /*
396 * nEntries counts leaf tuples, so increment it only when we make a
397 * new one.
398 */
399 if (buildStats)
400 buildStats->nEntries++;
401 }
402
403 /* Insert the new or modified leaf tuple */
404 insertdata.entry = itup;
405 ginInsertValue(&btree, stack, &insertdata, buildStats);
406 pfree(itup);
407}
#define GinIsPostingTree(itup)
Definition: ginblock.h:231
#define GinGetPostingTree(itup)
Definition: ginblock.h:233
void freeGinBtreeStack(GinBtreeStack *stack)
Definition: ginbtree.c:198
void ginInsertValue(GinBtree btree, GinBtreeStack *stack, void *insertdata, GinStatsData *buildStats)
Definition: ginbtree.c:816
GinBtreeStack * ginFindLeafPage(GinBtree btree, bool searchMode, bool rootConflictCheck)
Definition: ginbtree.c:83
void ginPrepareEntryScan(GinBtree btree, OffsetNumber attnum, Datum key, GinNullCategory category, GinState *ginstate)
Definition: ginentrypage.c:747
static IndexTuple addItemPointersToLeafTuple(GinState *ginstate, IndexTuple old, ItemPointerData *items, uint32 nitem, GinStatsData *buildStats, Buffer buffer)
Definition: gininsert.c:209
static IndexTuple buildFreshLeafTuple(GinState *ginstate, OffsetNumber attnum, Datum key, GinNullCategory category, ItemPointerData *items, uint32 nitem, GinStatsData *buildStats, Buffer buffer)
Definition: gininsert.c:289
void CheckForSerializableConflictIn(Relation relation, ItemPointer tid, BlockNumber blkno)
Definition: predicate.c:4336
bool(* findItem)(GinBtree, GinBtreeStack *)
Definition: gin_private.h:157
OffsetNumber off
Definition: gin_private.h:134
Relation index
Definition: gin_private.h:59
int64 nEntries
Definition: gin.h:61

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

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

◆ ginExtractEntries()

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

Definition at line 488 of file ginutil.c.

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

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

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

◆ ginFindLeafPage()

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

Definition at line 83 of file ginbtree.c.

85{
86 GinBtreeStack *stack;
87
88 stack = (GinBtreeStack *) palloc(sizeof(GinBtreeStack));
89 stack->blkno = btree->rootBlkno;
90 stack->buffer = ReadBuffer(btree->index, btree->rootBlkno);
91 stack->parent = NULL;
92 stack->predictNumber = 1;
93
94 if (rootConflictCheck)
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:3014
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:758
#define GinPageIsIncompleteSplit(page)
Definition: ginblock.h:127
int ginTraverseLock(Buffer buffer, bool searchMode)
Definition: ginbtree.c:39
static void ginFinishOldSplit(GinBtree btree, GinBtreeStack *stack, GinStatsData *buildStats, int access)
Definition: ginbtree.c:779
Buffer ginStepRight(Buffer buffer, Relation index, int lockmode)
Definition: ginbtree.c:177
short access
Definition: preproc-type.c:36
BlockNumber(* findChildPage)(GinBtree, GinBtreeStack *)
Definition: gin_private.h:154
bool(* isMoveRight)(GinBtree, Page)
Definition: gin_private.h:156
Relation index
Definition: gin_private.h:168
BlockNumber rootBlkno
Definition: gin_private.h:169
uint32 predictNumber
Definition: gin_private.h:137
BlockNumber blkno
Definition: gin_private.h:132

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

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

◆ GinFormTuple()

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

Definition at line 44 of file ginentrypage.c.

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

References Assert(), attnum, data, ereport, errcode(), errmsg(), ERROR, GIN_CAT_NORM_KEY, GinCategoryOffset, GinGetPosting, GinMaxItemSize, GinSetNPosting, GinSetNullCategory, GinSetPostingOffset, GinState::index, index_form_tuple(), IndexTupleHasNulls(), IndexTupleSize(), sort-test::key, Max, MAXALIGN, GinState::oneCol, pfree(), RelationGetRelationName, repalloc(), SHORTALIGN, IndexTupleData::t_info, GinState::tupdesc, and UInt16GetDatum().

Referenced by addItemPointersToLeafTuple(), buildFreshLeafTuple(), ginHeapTupleFastCollect(), and ginVacuumEntryPage().

◆ ginFreeScanKeys()

void ginFreeScanKeys ( GinScanOpaque  so)

Definition at line 239 of file ginscan.c.

240{
241 uint32 i;
242
243 if (so->keys == NULL)
244 return;
245
246 for (i = 0; i < so->totalentries; i++)
247 {
248 GinScanEntry entry = so->entries[i];
249
250 if (entry->buffer != InvalidBuffer)
251 ReleaseBuffer(entry->buffer);
252 if (entry->list)
253 pfree(entry->list);
254 if (entry->matchIterator)
256 if (entry->matchBitmap)
257 tbm_free(entry->matchBitmap);
258 }
259
261
262 so->keys = NULL;
263 so->nkeys = 0;
264 so->entries = NULL;
265 so->totalentries = 0;
266}
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:414
TIDBitmap * matchBitmap
Definition: gin_private.h:355
ItemPointerData * list
Definition: gin_private.h:367
TBMPrivateIterator * matchIterator
Definition: gin_private.h:356
GinScanEntry * entries
Definition: gin_private.h:385
void tbm_free(TIDBitmap *tbm)
Definition: tidbitmap.c:311
void tbm_end_private_iterate(TBMPrivateIterator *iterator)
Definition: tidbitmap.c:1150

References GinScanEntryData::buffer, GinScanOpaqueData::entries, i, InvalidBuffer, GinScanOpaqueData::keyCtx, GinScanOpaqueData::keys, GinScanEntryData::list, GinScanEntryData::matchBitmap, GinScanEntryData::matchIterator, MemoryContextReset(), GinScanOpaqueData::nkeys, pfree(), ReleaseBuffer(), tbm_end_private_iterate(), tbm_free(), and GinScanOpaqueData::totalentries.

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

◆ ginGetBAEntry()

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

Definition at line 268 of file ginbulk.c.

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

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

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

◆ gingetbitmap()

int64 gingetbitmap ( IndexScanDesc  scan,
TIDBitmap tbm 
)

Definition at line 1929 of file ginget.c.

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

References CHECK_FOR_INTERRUPTS, ginFreeScanKeys(), GinIsVoidRes, ginNewScanKey(), ItemPointerGetBlockNumber(), ItemPointerIsLossyPage, ItemPointerSetMin, IndexScanDescData::opaque, scanGetItem(), scanPendingInsert(), startScan(), tbm_add_page(), and tbm_add_tuples().

Referenced by ginhandler().

◆ ginHeapTupleFastCollect()

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

Definition at line 483 of file ginfast.c.

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

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

Referenced by gininsert().

◆ ginHeapTupleFastInsert()

void ginHeapTupleFastInsert ( GinState ginstate,
GinTupleCollector collector 
)

Definition at line 219 of file ginfast.c.

220{
221 Relation index = ginstate->index;
222 Buffer metabuffer;
223 Page metapage;
224 GinMetaPageData *metadata = NULL;
225 Buffer buffer = InvalidBuffer;
226 Page page = NULL;
228 bool separateList = false;
229 bool needCleanup = false;
230 int cleanupSize;
231 bool needWal;
232
233 if (collector->ntuples == 0)
234 return;
235
236 needWal = RelationNeedsWAL(index);
237
238 data.locator = index->rd_locator;
239 data.ntuples = 0;
240 data.newRightlink = data.prevTail = InvalidBlockNumber;
241
242 metabuffer = ReadBuffer(index, GIN_METAPAGE_BLKNO);
243 metapage = BufferGetPage(metabuffer);
244
245 /*
246 * An insertion to the pending list could logically belong anywhere in the
247 * tree, so it conflicts with all serializable scans. All scans acquire a
248 * predicate lock on the metabuffer to represent that. Therefore we'll
249 * check for conflicts in, but not until we have the page locked and are
250 * ready to modify the page.
251 */
252
253 if (collector->sumsize + collector->ntuples * sizeof(ItemIdData) > GinListPageSize)
254 {
255 /*
256 * Total size is greater than one page => make sublist
257 */
258 separateList = true;
259 }
260 else
261 {
262 LockBuffer(metabuffer, GIN_EXCLUSIVE);
263 metadata = GinPageGetMeta(metapage);
264
265 if (metadata->head == InvalidBlockNumber ||
266 collector->sumsize + collector->ntuples * sizeof(ItemIdData) > metadata->tailFreeSize)
267 {
268 /*
269 * Pending list is empty or total size is greater than freespace
270 * on tail page => make sublist
271 *
272 * We unlock metabuffer to keep high concurrency
273 */
274 separateList = true;
275 LockBuffer(metabuffer, GIN_UNLOCK);
276 }
277 }
278
279 if (separateList)
280 {
281 /*
282 * We should make sublist separately and append it to the tail
283 */
284 GinMetaPageData sublist;
285
286 memset(&sublist, 0, sizeof(GinMetaPageData));
287 makeSublist(index, collector->tuples, collector->ntuples, &sublist);
288
289 /*
290 * metapage was unlocked, see above
291 */
292 LockBuffer(metabuffer, GIN_EXCLUSIVE);
293 metadata = GinPageGetMeta(metapage);
294
296
297 if (metadata->head == InvalidBlockNumber)
298 {
299 /*
300 * Main list is empty, so just insert sublist as main list
301 */
303
304 metadata->head = sublist.head;
305 metadata->tail = sublist.tail;
306 metadata->tailFreeSize = sublist.tailFreeSize;
307
308 metadata->nPendingPages = sublist.nPendingPages;
309 metadata->nPendingHeapTuples = sublist.nPendingHeapTuples;
310
311 if (needWal)
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, (Item) collector->tuples[i], tupsize, off, false, false);
388
389 if (l == InvalidOffsetNumber)
390 elog(ERROR, "failed to add item to index page in \"%s\"",
392
393 memcpy(ptr, collector->tuples[i], tupsize);
394 ptr += tupsize;
395
396 off++;
397 }
398
399 Assert((ptr - collectordata) <= collector->sumsize);
400
401 MarkBufferDirty(buffer);
402
403 if (needWal)
404 {
406 XLogRegisterBufData(1, collectordata, collector->sumsize);
407 }
408
409 metadata->tailFreeSize = PageGetExactFreeSpace(page);
410 }
411
412 /*
413 * Set pd_lower just past the end of the metadata. This is essential,
414 * because without doing so, metadata will be lost if xlog.c compresses
415 * the page. (We must do this here because pre-v11 versions of PG did not
416 * set the metapage's pd_lower correctly, so a pg_upgraded index might
417 * contain the wrong value.)
418 */
419 ((PageHeader) metapage)->pd_lower =
420 ((char *) metadata + sizeof(GinMetaPageData)) - (char *) metapage;
421
422 /*
423 * Write metabuffer, make xlog entry
424 */
425 MarkBufferDirty(metabuffer);
426
427 if (needWal)
428 {
429 XLogRecPtr recptr;
430
431 memcpy(&data.metadata, metadata, sizeof(GinMetaPageData));
432
435
436 recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_UPDATE_META_PAGE);
437 PageSetLSN(metapage, recptr);
438
439 if (buffer != InvalidBuffer)
440 {
441 PageSetLSN(page, recptr);
442 }
443 }
444
445 if (buffer != InvalidBuffer)
446 UnlockReleaseBuffer(buffer);
447
448 /*
449 * Force pending list cleanup when it becomes too long. And,
450 * ginInsertCleanup could take significant amount of time, so we prefer to
451 * call it when it can do all the work in a single collection cycle. In
452 * non-vacuum mode, it shouldn't require maintenance_work_mem, so fire it
453 * while pending list is still small enough to fit into
454 * gin_pending_list_limit.
455 *
456 * ginInsertCleanup() should not be called inside our CRIT_SECTION.
457 */
458 cleanupSize = GinGetPendingListCleanupSize(index);
459 if (metadata->nPendingPages * GIN_PAGE_FREESIZE > cleanupSize * (Size) 1024)
460 needCleanup = true;
461
462 UnlockReleaseBuffer(metabuffer);
463
465
466 /*
467 * Since it could contend with concurrent cleanup process we cleanup
468 * pending list not forcibly.
469 */
470 if (needCleanup)
471 ginInsertCleanup(ginstate, false, true, false, NULL);
472}
Size PageGetExactFreeSpace(const PageData *page)
Definition: bufpage.c:957
static bool PageIsEmpty(const PageData *page)
Definition: bufpage.h:224
PageHeaderData * PageHeader
Definition: bufpage.h:174
#define GinGetPendingListCleanupSize(relation)
Definition: gin_private.h:39
#define GinListPageSize
Definition: ginblock.h:327
#define GIN_METAPAGE_BLKNO
Definition: ginblock.h:51
#define GinPageGetMeta(p)
Definition: ginblock.h:104
#define GIN_PAGE_FREESIZE
Definition: ginfast.c:41
static void makeSublist(Relation index, IndexTuple *tuples, int32 ntuples, GinMetaPageData *res)
Definition: ginfast.c:145
#define XLOG_GIN_UPDATE_META_PAGE
Definition: ginxlog.h:162
#define OffsetNumberNext(offsetNumber)
Definition: off.h:52
BlockNumber tail
Definition: ginblock.h:62
uint32 tailFreeSize
Definition: ginblock.h:67
BlockNumber nPendingPages
Definition: ginblock.h:73
int64 nPendingHeapTuples
Definition: ginblock.h:74
BlockNumber head
Definition: ginblock.h:61
void XLogRegisterBufData(uint8 block_id, const void *data, uint32 len)
Definition: xloginsert.c:405
#define REGBUF_STANDARD
Definition: xloginsert.h:35

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

Referenced by gininsert().

◆ ginInitBA()

void ginInitBA ( BuildAccumulator accum)

Definition at line 109 of file ginbulk.c.

110{
111 /* accum->ginstate is intentionally not set here */
112 accum->allocatedMemory = 0;
113 accum->entryallocator = NULL;
114 accum->eas_used = 0;
115 accum->tree = rbt_create(sizeof(GinEntryAccumulator),
119 NULL, /* no freefunc needed */
120 accum);
121}
static void ginCombineData(RBTNode *existing, const RBTNode *newdata, void *arg)
Definition: ginbulk.c:30
static 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
Definition: gin_private.h:443

References BuildAccumulator::allocatedMemory, cmpEntryAccumulator(), BuildAccumulator::eas_used, BuildAccumulator::entryallocator, 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 
)

Definition at line 355 of file ginutil.c.

356{
358}
static Size BufferGetPageSize(Buffer buffer)
Definition: bufmgr.h:406

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

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

◆ ginInitConsistentFunction()

void ginInitConsistentFunction ( GinState ginstate,
GinScanKey  key 
)

Definition at line 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:746
#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:83
FmgrInfo consistentFn[INDEX_MAX_KEYS]
Definition: gin_private.h:82

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

Referenced by ginFillScanKey().

◆ GinInitMetabuffer()

void GinInitMetabuffer ( Buffer  b)

Definition at line 361 of file ginutil.c.

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

References b, BufferGetPage(), BufferGetPageSize(), GIN_CURRENT_VERSION, GIN_META, GinInitPage(), GinPageGetMeta, GinMetaPageData::ginVersion, GinMetaPageData::head, InvalidBlockNumber, GinMetaPageData::nDataPages, GinMetaPageData::nEntries, GinMetaPageData::nEntryPages, GinMetaPageData::nPendingHeapTuples, GinMetaPageData::nPendingPages, GinMetaPageData::nTotalPages, GinMetaPageData::tail, and GinMetaPageData::tailFreeSize.

Referenced by ginbuild(), ginbuildempty(), ginRedoDeleteListPages(), and ginRedoUpdateMetapage().

◆ GinInitPage()

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

Definition at line 343 of file ginutil.c.

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

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

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

◆ gininsert()

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

Definition at line 824 of file gininsert.c.

829{
830 GinState *ginstate = (GinState *) indexInfo->ii_AmCache;
831 MemoryContext oldCtx;
832 MemoryContext insertCtx;
833 int i;
834
835 /* Initialize GinState cache if first call in this statement */
836 if (ginstate == NULL)
837 {
838 oldCtx = MemoryContextSwitchTo(indexInfo->ii_Context);
839 ginstate = (GinState *) palloc(sizeof(GinState));
840 initGinState(ginstate, index);
841 indexInfo->ii_AmCache = ginstate;
842 MemoryContextSwitchTo(oldCtx);
843 }
844
846 "Gin insert temporary context",
848
849 oldCtx = MemoryContextSwitchTo(insertCtx);
850
852 {
853 GinTupleCollector collector;
854
855 memset(&collector, 0, sizeof(GinTupleCollector));
856
857 for (i = 0; i < ginstate->origTupdesc->natts; i++)
858 ginHeapTupleFastCollect(ginstate, &collector,
859 (OffsetNumber) (i + 1),
860 values[i], isnull[i],
861 ht_ctid);
862
863 ginHeapTupleFastInsert(ginstate, &collector);
864 }
865 else
866 {
867 for (i = 0; i < ginstate->origTupdesc->natts; i++)
868 ginHeapTupleInsert(ginstate, (OffsetNumber) (i + 1),
869 values[i], isnull[i],
870 ht_ctid);
871 }
872
873 MemoryContextSwitchTo(oldCtx);
874 MemoryContextDelete(insertCtx);
875
876 return false;
877}
static Datum values[MAXATTR]
Definition: bootstrap.c:151
#define GinGetUseFastUpdate(relation)
Definition: gin_private.h:34
void ginHeapTupleFastCollect(GinState *ginstate, GinTupleCollector *collector, OffsetNumber attnum, Datum value, bool isNull, ItemPointer ht_ctid)
Definition: ginfast.c:483
void ginHeapTupleFastInsert(GinState *ginstate, GinTupleCollector *collector)
Definition: ginfast.c:219
static void ginHeapTupleInsert(GinState *ginstate, OffsetNumber attnum, Datum value, bool isNull, ItemPointer item)
Definition: gininsert.c:806
TupleDesc origTupdesc
Definition: gin_private.h:73
void * ii_AmCache
Definition: execnodes.h:220
MemoryContext ii_Context
Definition: execnodes.h:221

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

Referenced by ginhandler().

◆ ginInsertBAEntries()

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

Definition at line 210 of file ginbulk.c.

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

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

Referenced by ginHeapTupleBulkInsert(), and processPendingPage().

◆ ginInsertCleanup()

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

Definition at line 780 of file ginfast.c.

783{
784 Relation index = ginstate->index;
785 Buffer metabuffer,
786 buffer;
787 Page metapage,
788 page;
789 GinMetaPageData *metadata;
791 oldCtx;
792 BuildAccumulator accum;
793 KeyArray datums;
794 BlockNumber blkno,
795 blknoFinish;
796 bool cleanupFinish = false;
797 bool fsm_vac = false;
798 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;
827 workMemory = work_mem;
828 }
829
830 metabuffer = ReadBuffer(index, GIN_METAPAGE_BLKNO);
831 LockBuffer(metabuffer, GIN_SHARE);
832 metapage = BufferGetPage(metabuffer);
833 metadata = GinPageGetMeta(metapage);
834
835 if (metadata->head == InvalidBlockNumber)
836 {
837 /* Nothing to do */
838 UnlockReleaseBuffer(metabuffer);
840 return;
841 }
842
843 /*
844 * Remember a tail page to prevent infinite cleanup if other backends add
845 * new tuples faster than we can cleanup.
846 */
847 blknoFinish = metadata->tail;
848
849 /*
850 * Read and lock head of pending list
851 */
852 blkno = metadata->head;
853 buffer = ReadBuffer(index, blkno);
854 LockBuffer(buffer, GIN_SHARE);
855 page = BufferGetPage(buffer);
856
857 LockBuffer(metabuffer, GIN_UNLOCK);
858
859 /*
860 * Initialize. All temporary space will be in opCtx
861 */
863 "GIN insert cleanup temporary context",
865
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 */
938 LockBuffer(metabuffer, GIN_EXCLUSIVE);
939 LockBuffer(buffer, GIN_SHARE);
940
941 Assert(!GinPageIsDeleted(page));
942
943 /*
944 * While we left the page unlocked, more stuff might have gotten
945 * added to it. If so, process those entries immediately. There
946 * shouldn't be very many, so we don't worry about the fact that
947 * we're doing this with exclusive lock. Insertion algorithm
948 * guarantees that inserted row(s) will not continue on next page.
949 * NOTE: intentionally no vacuum_delay_point in this loop.
950 */
951 if (PageGetMaxOffsetNumber(page) != maxoff)
952 {
953 ginInitBA(&accum);
954 processPendingPage(&accum, &datums, page, maxoff + 1);
955
956 ginBeginBAScan(&accum);
957 while ((list = ginGetBAEntry(&accum,
958 &attnum, &key, &category, &nlist)) != NULL)
959 ginEntryInsert(ginstate, attnum, key, category,
960 list, nlist, NULL);
961 }
962
963 /*
964 * Remember next page - it will become the new list head
965 */
966 blkno = GinPageGetOpaque(page)->rightlink;
967 UnlockReleaseBuffer(buffer); /* shiftList will do exclusive
968 * locking */
969
970 /*
971 * remove read pages from pending list, at this point all content
972 * of read pages is in regular structure
973 */
974 shiftList(index, metabuffer, blkno, fill_fsm, stats);
975
976 /* At this point, some pending pages have been freed up */
977 fsm_vac = true;
978
979 Assert(blkno == metadata->head);
980 LockBuffer(metabuffer, GIN_UNLOCK);
981
982 /*
983 * if we removed the whole pending list or we cleanup tail (which
984 * we remembered on start our cleanup process) then just exit
985 */
986 if (blkno == InvalidBlockNumber || cleanupFinish)
987 break;
988
989 /*
990 * release memory used so far and reinit state
991 */
993 initKeyArray(&datums, datums.maxvalues);
994 ginInitBA(&accum);
995 }
996 else
997 {
998 blkno = GinPageGetOpaque(page)->rightlink;
999 UnlockReleaseBuffer(buffer);
1000 }
1001
1002 /*
1003 * Read next page in pending list
1004 */
1005 vacuum_delay_point(false);
1006 buffer = ReadBuffer(index, blkno);
1007 LockBuffer(buffer, GIN_SHARE);
1008 page = BufferGetPage(buffer);
1009 }
1010
1012 ReleaseBuffer(metabuffer);
1013
1014 /*
1015 * As pending list pages can have a high churn rate, it is desirable to
1016 * recycle them immediately to the FreeSpaceMap when ordinary backends
1017 * clean the list.
1018 */
1019 if (fsm_vac && fill_fsm)
1021
1022 /* Clean up temporary space */
1023 MemoryContextSwitchTo(oldCtx);
1025}
int autovacuum_work_mem
Definition: autovacuum.c:121
#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:132
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
int32 maxvalues
Definition: ginfast.c:49

References BuildAccumulator::allocatedMemory, ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, AmAutoVacuumWorkerProcess, Assert(), attnum, autovacuum_work_mem, BufferGetPage(), ConditionalLockPage(), CurrentMemoryContext, ExclusiveLock, FirstOffsetNumber, GIN_EXCLUSIVE, GIN_METAPAGE_BLKNO, GIN_SHARE, GIN_UNLOCK, ginBeginBAScan(), ginEntryInsert(), ginGetBAEntry(), ginInitBA(), GinPageGetMeta, GinPageGetOpaque, GinPageHasFullRow, GinPageIsDeleted, BuildAccumulator::ginstate, GinMetaPageData::head, GinState::index, IndexFreeSpaceMapVacuum(), initKeyArray(), InvalidBlockNumber, sort-test::key, sort-test::list, LockBuffer(), LockPage(), maintenance_work_mem, KeyArray::maxvalues, MemoryContextDelete(), MemoryContextReset(), MemoryContextSwitchTo(), opCtx, PageGetMaxOffsetNumber(), processPendingPage(), ReadBuffer(), ReleaseBuffer(), shiftList(), GinMetaPageData::tail, UnlockPage(), UnlockReleaseBuffer(), vacuum_delay_point(), and work_mem.

Referenced by gin_clean_pending_list(), ginbulkdelete(), ginHeapTupleFastInsert(), and ginvacuumcleanup().

◆ ginInsertItemPointers()

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

Definition at line 1908 of file gindatapage.c.

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

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

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

◆ ginInsertValue()

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

Definition at line 816 of file ginbtree.c.

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

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

Referenced by ginEntryInsert(), and ginInsertItemPointers().

◆ ginMergeItemPointers()

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

Definition at line 378 of file ginpostinglist.c.

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

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

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

◆ GinNewBuffer()

Buffer GinNewBuffer ( Relation  index)

Definition at line 305 of file ginutil.c.

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

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

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

◆ ginNewScanKey()

void ginNewScanKey ( IndexScanDesc  scan)

Definition at line 269 of file ginscan.c.

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

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

Referenced by gingetbitmap().

◆ ginoptions()

bytea * ginoptions ( Datum  reloptions,
bool  validate 
)

Definition at line 607 of file ginutil.c.

608{
609 static const relopt_parse_elt tab[] = {
610 {"fastupdate", RELOPT_TYPE_BOOL, offsetof(GinOptions, useFastUpdate)},
611 {"gin_pending_list_limit", RELOPT_TYPE_INT, offsetof(GinOptions,
612 pendingListCleanupSize)}
613 };
614
615 return (bytea *) build_reloptions(reloptions, validate,
617 sizeof(GinOptions),
618 tab, lengthof(tab));
619}
static bool validate(Port *port, const char *auth)
Definition: auth-oauth.c:638
#define lengthof(array)
Definition: c.h:759
void * build_reloptions(Datum reloptions, bool validate, relopt_kind kind, Size relopt_struct_size, const relopt_parse_elt *relopt_elems, int num_relopt_elems)
Definition: reloptions.c:1934
@ RELOPT_KIND_GIN
Definition: reloptions.h:46
@ RELOPT_TYPE_INT
Definition: reloptions.h:32
@ RELOPT_TYPE_BOOL
Definition: reloptions.h:31
Definition: c.h:658

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

Referenced by ginhandler().

◆ GinPageDeletePostingItem()

void GinPageDeletePostingItem ( Page  page,
OffsetNumber  offset 
)

Definition at line 417 of file gindatapage.c.

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

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

Referenced by ginDeletePage(), and ginRedoDeletePage().

◆ ginPostingListDecode()

◆ ginPostingListDecodeAllSegments()

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

Definition at line 297 of file ginpostinglist.c.

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

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

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

◆ ginPostingListDecodeAllSegmentsToTbm()

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

Definition at line 358 of file ginpostinglist.c.

360{
361 int ndecoded;
363
364 items = ginPostingListDecodeAllSegments(ptr, len, &ndecoded);
365 tbm_add_tuples(tbm, items, ndecoded, false);
366 pfree(items);
367
368 return ndecoded;
369}

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

Referenced by GinDataLeafPageGetItemsToTbm().

◆ ginPrepareEntryScan()

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

Definition at line 747 of file ginentrypage.c.

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

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

Referenced by ginEntryInsert(), and startScanEntry().

◆ ginReadTuple()

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

Definition at line 162 of file ginentrypage.c.

164{
165 Pointer ptr = GinGetPosting(itup);
166 int nipd = GinGetNPosting(itup);
167 ItemPointer ipd;
168 int ndecoded;
169
170 if (GinItupIsCompressed(itup))
171 {
172 if (nipd > 0)
173 {
174 ipd = ginPostingListDecode((GinPostingList *) ptr, &ndecoded);
175 if (nipd != ndecoded)
176 elog(ERROR, "number of items mismatch in GIN entry tuple, %d in tuple header, %d decoded",
177 nipd, ndecoded);
178 }
179 else
180 {
181 ipd = palloc(0);
182 }
183 }
184 else
185 {
186 ipd = (ItemPointer) palloc(sizeof(ItemPointerData) * nipd);
187 memcpy(ipd, ptr, sizeof(ItemPointerData) * nipd);
188 }
189 *nitems = nipd;
190 return ipd;
191}
#define GinItupIsCompressed(itup)
Definition: ginblock.h:239
#define GinGetNPosting(itup)
Definition: ginblock.h:228

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

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

◆ ginrescan()

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

Definition at line 450 of file ginscan.c.

452{
454
455 ginFreeScanKeys(so);
456
457 if (scankey && scan->numberOfKeys > 0)
458 memcpy(scan->keyData, scankey, scan->numberOfKeys * sizeof(ScanKeyData));
459}

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

Referenced by ginhandler().

◆ ginScanBeginPostingTree()

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

Definition at line 1936 of file gindatapage.c.

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

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

Referenced by scanPostingTree(), and startScanEntry().

◆ ginStepRight()

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

Definition at line 177 of file ginbtree.c.

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

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

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

◆ ginTraverseLock()

int ginTraverseLock ( Buffer  buffer,
bool  searchMode 
)

Definition at line 39 of file ginbtree.c.

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

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

Referenced by ginFindLeafPage().

◆ gintuple_get_attrnum()

OffsetNumber gintuple_get_attrnum ( GinState ginstate,
IndexTuple  tuple 
)

Definition at line 231 of file ginutil.c.

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

References Assert(), DatumGetUInt16(), 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 
)

Definition at line 264 of file ginutil.c.

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

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

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

◆ ginvacuumcleanup()

IndexBulkDeleteResult * ginvacuumcleanup ( IndexVacuumInfo info,
IndexBulkDeleteResult stats 
)

Definition at line 687 of file ginvacuum.c.

688{
689 Relation index = info->index;
690 bool needLock;
691 BlockNumber npages,
692 blkno;
693 BlockNumber totFreePages;
694 GinState ginstate;
695 GinStatsData idxStat;
696
697 /*
698 * In an autovacuum analyze, we want to clean up pending insertions.
699 * Otherwise, an ANALYZE-only call is a no-op.
700 */
701 if (info->analyze_only)
702 {
704 {
705 initGinState(&ginstate, index);
706 ginInsertCleanup(&ginstate, false, true, true, stats);
707 }
708 return stats;
709 }
710
711 /*
712 * Set up all-zero stats and cleanup pending inserts if ginbulkdelete
713 * wasn't called
714 */
715 if (stats == NULL)
716 {
718 initGinState(&ginstate, index);
720 false, true, stats);
721 }
722
723 memset(&idxStat, 0, sizeof(idxStat));
724
725 /*
726 * XXX we always report the heap tuple count as the number of index
727 * entries. This is bogus if the index is partial, but it's real hard to
728 * tell how many distinct heap entries are referenced by a GIN index.
729 */
730 stats->num_index_tuples = Max(info->num_heap_tuples, 0);
731 stats->estimated_count = info->estimated_count;
732
733 /*
734 * Need lock unless it's local to this backend.
735 */
736 needLock = !RELATION_IS_LOCAL(index);
737
738 if (needLock)
741 if (needLock)
743
744 totFreePages = 0;
745
746 for (blkno = GIN_ROOT_BLKNO; blkno < npages; blkno++)
747 {
748 Buffer buffer;
749 Page page;
750
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 = (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:659
BlockNumber pages_free
Definition: genam.h:106
BlockNumber num_pages
Definition: genam.h:100
double num_heap_tuples
Definition: genam.h:75
bool analyze_only
Definition: genam.h:71
bool estimated_count
Definition: genam.h:73

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

Referenced by ginhandler().

◆ ginVacuumItemPointers()

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

Definition at line 47 of file ginvacuum.c.

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

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

Referenced by ginVacuumEntryPage(), and ginVacuumPostingTreeLeaf().

◆ ginVacuumPostingTreeLeaf()

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

Definition at line 738 of file gindatapage.c.

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

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

Referenced by ginVacuumPostingTreeLeaves().

◆ ginvalidate()

bool ginvalidate ( Oid  opclassoid)

Definition at line 31 of file ginvalidate.c.

32{
33 bool result = true;
34 HeapTuple classtup;
35 Form_pg_opclass classform;
36 Oid opfamilyoid;
37 Oid opcintype;
38 Oid opckeytype;
39 char *opclassname;
40 char *opfamilyname;
41 CatCList *proclist,
42 *oprlist;
43 List *grouplist;
44 OpFamilyOpFuncGroup *opclassgroup;
45 int i;
46 ListCell *lc;
47
48 /* Fetch opclass information */
49 classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
50 if (!HeapTupleIsValid(classtup))
51 elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
52 classform = (Form_pg_opclass) GETSTRUCT(classtup);
53
54 opfamilyoid = classform->opcfamily;
55 opcintype = classform->opcintype;
56 opckeytype = classform->opckeytype;
57 if (!OidIsValid(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 */
65 oprlist = SearchSysCacheList1(AMOPSTRATEGY, ObjectIdGetDatum(opfamilyoid));
66 proclist = SearchSysCacheList1(AMPROCNUM, ObjectIdGetDatum(opfamilyoid));
67
68 /* Check individual support functions */
69 for (i = 0; i < proclist->n_members; i++)
70 {
71 HeapTuple proctup = &proclist->members[i]->tuple;
72 Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
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 {
82 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
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 */
105 ok = check_amproc_signature(procform->amproc, INTERNALOID, false,
106 2, 3, opcintype, INTERNALOID,
107 INTERNALOID);
108 break;
110 /* Some opclasses omit nullFlags and searchMode */
111 ok = check_amproc_signature(procform->amproc, INTERNALOID, false,
112 5, 7, opcintype, INTERNALOID,
113 INT2OID, INTERNALOID, INTERNALOID,
114 INTERNALOID, 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,
121 INTERNALOID, INTERNALOID,
122 INTERNALOID, INTERNALOID);
123 break;
125 ok = check_amproc_signature(procform->amproc, INT4OID, false,
126 4, 4, opckeytype, opckeytype,
127 INT2OID, INTERNALOID);
128 break;
130 ok = check_amproc_signature(procform->amproc, CHAROID, false,
131 7, 7, INTERNALOID, INT2OID,
132 opcintype, INT4OID,
133 INTERNALOID, INTERNALOID,
134 INTERNALOID);
135 break;
136 case GIN_OPTIONS_PROC:
137 ok = check_amoptsproc_signature(procform->amproc);
138 break;
139 default:
141 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
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 {
153 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
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;
166 Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
167
168 /* TODO: Check that only allowed strategy numbers exist */
169 if (oprform->amopstrategy < 1 || oprform->amopstrategy > 63)
170 {
172 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
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 {
185 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
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 {
198 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
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 */
207 grouplist = identify_opfamily_groups(oprlist, proclist);
208 opclassgroup = NULL;
209 foreach(lc, grouplist)
210 {
212
213 /* Remember the group exactly matching the test opclass */
214 if (thisgroup->lefttype == opcintype &&
215 thisgroup->righttype == opcintype)
216 opclassgroup = thisgroup;
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 */
240 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
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 {
250 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
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
258 ReleaseCatCacheList(proclist);
259 ReleaseCatCacheList(oprlist);
260 ReleaseSysCache(classtup);
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:717
void ReleaseCatCacheList(CatCList *list)
Definition: catcache.c:2093
#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)
Definition: htup_details.h:728
char * get_opfamily_name(Oid opfid, bool missing_ok)
Definition: lsyscache.c:1393
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:257
unsigned int Oid
Definition: postgres_ext.h:30
char * format_procedure(Oid procedure_oid)
Definition: regproc.c:299
char * format_operator(Oid operator_oid)
Definition: regproc.c:793
Definition: pg_list.h:54
CatCTup * members[FLEXIBLE_ARRAY_MEMBER]
Definition: catcache.h:180
int n_members
Definition: catcache.h:178
HeapTupleData tuple
Definition: catcache.h:123
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221
#define SearchSysCacheList1(cacheId, key1)
Definition: syscache.h:127

References check_amop_signature(), check_amoptsproc_signature(), check_amproc_signature(), elog, ereport, errcode(), errmsg(), ERROR, format_operator(), format_procedure(), OpFamilyOpFuncGroup::functionset, 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, OpFamilyOpFuncGroup::lefttype, lfirst, catclist::members, catclist::n_members, NameStr, ObjectIdGetDatum(), OidIsValid, ReleaseCatCacheList(), ReleaseSysCache(), OpFamilyOpFuncGroup::righttype, SearchSysCache1(), SearchSysCacheList1, and catctup::tuple.

Referenced by ginhandler().

◆ initGinState()

void initGinState ( GinState state,
Relation  index 
)

Definition at line 102 of file ginutil.c.

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