PostgreSQL Source Code git master
gin_private.h File Reference
#include "access/amapi.h"
#include "access/gin.h"
#include "access/ginblock.h"
#include "access/itup.h"
#include "common/int.h"
#include "catalog/pg_am_d.h"
#include "fmgr.h"
#include "lib/rbtree.h"
#include "storage/bufmgr.h"
Include dependency graph for gin_private.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

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

Macros

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

Typedefs

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

Enumerations

enum  GinPlaceToPageRC { GPTP_NO_WORK , GPTP_INSERT , GPTP_SPLIT }
 

Functions

byteaginoptions (Datum reloptions, bool validate)
 
void initGinState (GinState *state, Relation index)
 
Buffer GinNewBuffer (Relation index)
 
void GinInitBuffer (Buffer b, uint32 f)
 
void GinInitPage (Page page, uint32 f, Size pageSize)
 
void GinInitMetabuffer (Buffer b)
 
int ginCompareEntries (GinState *ginstate, OffsetNumber attnum, Datum a, GinNullCategory categorya, Datum b, GinNullCategory categoryb)
 
int ginCompareAttEntries (GinState *ginstate, OffsetNumber attnuma, Datum a, GinNullCategory categorya, OffsetNumber attnumb, Datum b, GinNullCategory categoryb)
 
DatumginExtractEntries (GinState *ginstate, OffsetNumber attnum, Datum value, bool isNull, int32 *nentries, GinNullCategory **categories)
 
OffsetNumber gintuple_get_attrnum (GinState *ginstate, IndexTuple tuple)
 
Datum gintuple_get_key (GinState *ginstate, IndexTuple tuple, GinNullCategory *category)
 
IndexBuildResultginbuild (Relation heap, Relation index, struct IndexInfo *indexInfo)
 
void ginbuildempty (Relation index)
 
bool gininsert (Relation index, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, IndexUniqueCheck checkUnique, bool indexUnchanged, struct IndexInfo *indexInfo)
 
void ginEntryInsert (GinState *ginstate, OffsetNumber attnum, Datum key, GinNullCategory category, ItemPointerData *items, uint32 nitem, GinStatsData *buildStats)
 
GinBtreeStackginFindLeafPage (GinBtree btree, bool searchMode, bool rootConflictCheck)
 
Buffer ginStepRight (Buffer buffer, Relation index, int lockmode)
 
void freeGinBtreeStack (GinBtreeStack *stack)
 
void ginInsertValue (GinBtree btree, GinBtreeStack *stack, void *insertdata, GinStatsData *buildStats)
 
IndexTuple GinFormTuple (GinState *ginstate, OffsetNumber attnum, Datum key, GinNullCategory category, Pointer data, Size dataSize, int nipd, bool errorTooBig)
 
void ginPrepareEntryScan (GinBtree btree, OffsetNumber attnum, Datum key, GinNullCategory category, GinState *ginstate)
 
void ginEntryFillRoot (GinBtree btree, Page root, BlockNumber lblkno, Page lpage, BlockNumber rblkno, Page rpage)
 
ItemPointer ginReadTuple (GinState *ginstate, OffsetNumber attnum, IndexTuple itup, int *nitems)
 
ItemPointer GinDataLeafPageGetItems (Page page, int *nitems, ItemPointerData advancePast)
 
int GinDataLeafPageGetItemsToTbm (Page page, TIDBitmap *tbm)
 
BlockNumber createPostingTree (Relation index, ItemPointerData *items, uint32 nitems, GinStatsData *buildStats, Buffer entrybuffer)
 
void GinDataPageAddPostingItem (Page page, PostingItem *data, OffsetNumber offset)
 
void GinPageDeletePostingItem (Page page, OffsetNumber offset)
 
void ginInsertItemPointers (Relation index, BlockNumber rootBlkno, ItemPointerData *items, uint32 nitem, GinStatsData *buildStats)
 
GinBtreeStackginScanBeginPostingTree (GinBtree btree, Relation index, BlockNumber rootBlkno)
 
void ginDataFillRoot (GinBtree btree, Page root, BlockNumber lblkno, Page lpage, BlockNumber rblkno, Page rpage)
 
void ginVacuumPostingTreeLeaf (Relation indexrel, Buffer buffer, GinVacuumState *gvs)
 
IndexScanDesc ginbeginscan (Relation rel, int nkeys, int norderbys)
 
void ginendscan (IndexScanDesc scan)
 
void ginrescan (IndexScanDesc scan, ScanKey scankey, int nscankeys, ScanKey orderbys, int norderbys)
 
void ginNewScanKey (IndexScanDesc scan)
 
void ginFreeScanKeys (GinScanOpaque so)
 
int64 gingetbitmap (IndexScanDesc scan, TIDBitmap *tbm)
 
void ginInitConsistentFunction (GinState *ginstate, GinScanKey key)
 
IndexBulkDeleteResultginbulkdelete (IndexVacuumInfo *info, IndexBulkDeleteResult *stats, IndexBulkDeleteCallback callback, void *callback_state)
 
IndexBulkDeleteResultginvacuumcleanup (IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
 
ItemPointer ginVacuumItemPointers (GinVacuumState *gvs, ItemPointerData *items, int nitem, int *nremaining)
 
bool ginvalidate (Oid opclassoid)
 
void ginadjustmembers (Oid opfamilyoid, Oid opclassoid, List *operators, List *functions)
 
void ginInitBA (BuildAccumulator *accum)
 
void ginInsertBAEntries (BuildAccumulator *accum, ItemPointer heapptr, OffsetNumber attnum, Datum *entries, GinNullCategory *categories, int32 nentries)
 
void ginBeginBAScan (BuildAccumulator *accum)
 
ItemPointerDataginGetBAEntry (BuildAccumulator *accum, OffsetNumber *attnum, Datum *key, GinNullCategory *category, uint32 *n)
 
void ginHeapTupleFastInsert (GinState *ginstate, GinTupleCollector *collector)
 
void ginHeapTupleFastCollect (GinState *ginstate, GinTupleCollector *collector, OffsetNumber attnum, Datum value, bool isNull, ItemPointer ht_ctid)
 
void ginInsertCleanup (GinState *ginstate, bool full_clean, bool fill_fsm, bool forceCleanup, IndexBulkDeleteResult *stats)
 
GinPostingListginCompressPostingList (const ItemPointer ipd, int nipd, int maxsize, int *nwritten)
 
int ginPostingListDecodeAllSegmentsToTbm (GinPostingList *ptr, int len, TIDBitmap *tbm)
 
ItemPointer ginPostingListDecodeAllSegments (GinPostingList *segment, int len, int *ndecoded_out)
 
ItemPointer ginPostingListDecode (GinPostingList *plist, int *ndecoded_out)
 
ItemPointer ginMergeItemPointers (ItemPointerData *a, uint32 na, ItemPointerData *b, uint32 nb, int *nmerged)
 
static int ginCompareItemPointers (ItemPointer a, ItemPointer b)
 
int ginTraverseLock (Buffer buffer, bool searchMode)
 

Macro Definition Documentation

◆ GIN_DEFAULT_USE_FASTUPDATE

#define GIN_DEFAULT_USE_FASTUPDATE   true

Definition at line 33 of file gin_private.h.

◆ GIN_EXCLUSIVE

#define GIN_EXCLUSIVE   BUFFER_LOCK_EXCLUSIVE

Definition at line 51 of file gin_private.h.

◆ GIN_SHARE

#define GIN_SHARE   BUFFER_LOCK_SHARE

Definition at line 50 of file gin_private.h.

◆ GIN_UNLOCK

#define GIN_UNLOCK   BUFFER_LOCK_UNLOCK

Definition at line 49 of file gin_private.h.

◆ GinGetPendingListCleanupSize

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

Definition at line 39 of file gin_private.h.

◆ GinGetUseFastUpdate

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

Definition at line 34 of file gin_private.h.

Typedef Documentation

◆ GinBtree

typedef struct GinBtreeData* GinBtree

Definition at line 140 of file gin_private.h.

◆ GinBtreeData

typedef struct GinBtreeData GinBtreeData

◆ GinBtreeStack

typedef struct GinBtreeStack GinBtreeStack

◆ GinEntryAccumulator

◆ GinOptions

typedef struct GinOptions GinOptions

◆ GinScanEntry

typedef struct GinScanEntryData* GinScanEntry

Definition at line 266 of file gin_private.h.

◆ GinScanEntryData

◆ GinScanKey

typedef struct GinScanKeyData* GinScanKey

Definition at line 264 of file gin_private.h.

◆ GinScanKeyData

◆ GinScanOpaque

Definition at line 386 of file gin_private.h.

◆ GinScanOpaqueData

◆ GinState

typedef struct GinState GinState

◆ GinTupleCollector

◆ GinVacuumState

Definition at line 242 of file gin_private.h.

Enumeration Type Documentation

◆ GinPlaceToPageRC

Enumerator
GPTP_NO_WORK 
GPTP_INSERT 
GPTP_SPLIT 

Definition at line 143 of file gin_private.h.

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

Function Documentation

◆ createPostingTree()

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

Definition at line 1775 of file gindatapage.c.

1777{
1778 BlockNumber blkno;
1779 Buffer buffer;
1780 Page tmppage;
1781 Page page;
1782 Pointer ptr;
1783 int nrootitems;
1784 int rootsize;
1785 bool is_build = (buildStats != NULL);
1786
1787 /* Construct the new root page in memory first. */
1788 tmppage = (Page) palloc(BLCKSZ);
1789 GinInitPage(tmppage, GIN_DATA | GIN_LEAF | GIN_COMPRESSED, BLCKSZ);
1790 GinPageGetOpaque(tmppage)->rightlink = InvalidBlockNumber;
1791
1792 /*
1793 * Write as many of the items to the root page as fit. In segments of max
1794 * GinPostingListSegmentMaxSize bytes each.
1795 */
1796 nrootitems = 0;
1797 rootsize = 0;
1798 ptr = (Pointer) GinDataLeafPageGetPostingList(tmppage);
1799 while (nrootitems < nitems)
1800 {
1801 GinPostingList *segment;
1802 int npacked;
1803 int segsize;
1804
1805 segment = ginCompressPostingList(&items[nrootitems],
1806 nitems - nrootitems,
1808 &npacked);
1809 segsize = SizeOfGinPostingList(segment);
1810 if (rootsize + segsize > GinDataPageMaxDataSize)
1811 break;
1812
1813 memcpy(ptr, segment, segsize);
1814 ptr += segsize;
1815 rootsize += segsize;
1816 nrootitems += npacked;
1817 pfree(segment);
1818 }
1819 GinDataPageSetDataSize(tmppage, rootsize);
1820
1821 /*
1822 * All set. Get a new physical page, and copy the in-memory page to it.
1823 */
1824 buffer = GinNewBuffer(index);
1825 page = BufferGetPage(buffer);
1826 blkno = BufferGetBlockNumber(buffer);
1827
1828 /*
1829 * Copy any predicate locks from the entry tree leaf (containing posting
1830 * list) to the posting tree.
1831 */
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:3724
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:4941
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:2532
static Page BufferGetPage(Buffer buffer)
Definition: bufmgr.h:400
void PageRestoreTempPage(Page tempPage, Page oldPage)
Definition: bufpage.c:413
Pointer Page
Definition: bufpage.h:81
static void PageSetLSN(Page page, XLogRecPtr lsn)
Definition: bufpage.h:391
char * Pointer
Definition: c.h:479
#define DEBUG2
Definition: elog.h:29
#define elog(elevel,...)
Definition: elog.h:225
#define GIN_DATA
Definition: ginblock.h:41
#define GIN_COMPRESSED
Definition: ginblock.h:48
#define GinPageGetOpaque(page)
Definition: ginblock.h:110
#define SizeOfGinPostingList(plist)
Definition: ginblock.h:342
#define GIN_LEAF
Definition: ginblock.h:42
#define GinDataPageSetDataSize(page, size)
Definition: ginblock.h:309
#define GinDataPageMaxDataSize
Definition: ginblock.h:319
#define GinDataLeafPageGetPostingList(page)
Definition: ginblock.h:278
#define GinPostingListSegmentMaxSize
Definition: gindatapage.c:34
void ginInsertItemPointers(Relation index, BlockNumber rootBlkno, ItemPointerData *items, uint32 nitem, GinStatsData *buildStats)
Definition: gindatapage.c:1908
GinPostingList * ginCompressPostingList(const ItemPointer ipd, int nipd, int maxsize, int *nwritten)
void GinInitPage(Page page, uint32 f, Size pageSize)
Definition: ginutil.c:339
Buffer GinNewBuffer(Relation index)
Definition: ginutil.c:301
#define XLOG_GIN_CREATE_PTREE
Definition: ginxlog.h:19
#define nitems(x)
Definition: indent.h:31
void pfree(void *pointer)
Definition: mcxt.c:1521
void * palloc(Size size)
Definition: mcxt.c:1317
#define START_CRIT_SECTION()
Definition: miscadmin.h:149
#define END_CRIT_SECTION()
Definition: miscadmin.h:151
const void * data
void PredicateLockPageSplit(Relation relation, BlockNumber oldblkno, BlockNumber newblkno)
Definition: predicate.c:3134
#define RelationNeedsWAL(relation)
Definition: rel.h:628
BlockNumber nDataPages
Definition: gin.h:47
Definition: type.h:96
static ItemArray items
Definition: test_tidstore.c:48
uint64 XLogRecPtr
Definition: xlogdefs.h:21
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:474
void XLogRegisterData(const char *data, uint32 len)
Definition: xloginsert.c:364
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:242
void XLogBeginInsert(void)
Definition: xloginsert.c:149
#define REGBUF_WILL_INIT
Definition: xloginsert.h:33

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

Referenced by addItemPointersToLeafTuple(), and buildFreshLeafTuple().

◆ freeGinBtreeStack()

void freeGinBtreeStack ( GinBtreeStack stack)

Definition at line 198 of file ginbtree.c.

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

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

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

◆ ginadjustmembers()

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

Definition at line 277 of file ginvalidate.c.

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

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

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

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

◆ ginbeginscan()

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

Definition at line 25 of file ginscan.c.

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

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

Referenced by ginhandler().

◆ ginbuild()

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

Definition at line 317 of file gininsert.c.

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

References GinBuildState::accum, ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, attnum, GinBuildState::buildStats, CHECK_FOR_INTERRUPTS, CurrentMemoryContext, elog, END_CRIT_SECTION, ERROR, GinBuildState::funcCtx, GIN_LEAF, ginBeginBAScan(), ginBuildCallback(), ginEntryInsert(), ginGetBAEntry(), ginInitBA(), GinInitBuffer(), GinInitMetabuffer(), GinNewBuffer(), GinBuildState::ginstate, BuildAccumulator::ginstate, ginUpdateStats(), IndexBuildResult::heap_tuples, IndexBuildResult::index_tuples, GinBuildState::indtuples, initGinState(), sort-test::key, sort-test::list, log_newpage_range(), MAIN_FORKNUM, MarkBufferDirty(), MemoryContextDelete(), MemoryContextSwitchTo(), GinStatsData::nEntryPages, GinStatsData::nTotalPages, palloc(), RelationGetNumberOfBlocks, RelationGetRelationName, RelationNeedsWAL, START_CRIT_SECTION, table_index_build_scan(), GinBuildState::tmpCtx, and UnlockReleaseBuffer().

Referenced by ginhandler().

◆ ginbuildempty()

void ginbuildempty ( Relation  index)

Definition at line 433 of file gininsert.c.

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

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

Referenced by ginhandler().

◆ ginbulkdelete()

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

Definition at line 564 of file ginvacuum.c.

566{
567 Relation index = info->index;
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
666
667 for (i = 0; i < nRoot; i++)
668 {
669 ginVacuumPostingTree(&gvs, rootOfPostingTree[i]);
671 }
672
673 if (blkno == InvalidBlockNumber) /* rightmost page */
674 break;
675
676 buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
677 RBM_NORMAL, info->strategy);
678 LockBuffer(buffer, GIN_EXCLUSIVE);
679 }
680
682
683 return gvs.result;
684}
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:5158
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition: bufmgr.c:793
@ RBM_NORMAL
Definition: bufmgr.h:45
static Item PageGetItem(Page page, ItemId itemId)
Definition: bufpage.h:354
static ItemId PageGetItemId(Page page, OffsetNumber offsetNumber)
Definition: bufpage.h:243
static OffsetNumber PageGetMaxOffsetNumber(Page page)
Definition: bufpage.h:372
#define GIN_UNLOCK
Definition: gin_private.h:49
#define GIN_EXCLUSIVE
Definition: gin_private.h:51
#define GIN_SHARE
Definition: gin_private.h:50
#define GIN_ROOT_BLKNO
Definition: ginblock.h:52
#define GinGetDownlink(itup)
Definition: ginblock.h:257
#define GinPageIsData(page)
Definition: ginblock.h:115
#define GinPageIsLeaf(page)
Definition: ginblock.h:112
void ginInsertCleanup(GinState *ginstate, bool full_clean, bool fill_fsm, bool forceCleanup, IndexBulkDeleteResult *stats)
Definition: ginfast.c:780
static void xlogVacuumPage(Relation index, Buffer buffer)
Definition: ginvacuum.c:89
static void ginVacuumPostingTree(GinVacuumState *gvs, BlockNumber rootBlkno)
Definition: ginvacuum.c:408
static Page ginVacuumEntryPage(GinVacuumState *gvs, Buffer buffer, BlockNumber *roots, uint32 *nroot)
Definition: ginvacuum.c:455
int i
Definition: isn.c:72
IndexTupleData * IndexTuple
Definition: itup.h:53
struct IndexTupleData IndexTupleData
void * palloc0(Size size)
Definition: mcxt.c:1347
#define AmAutoVacuumWorkerProcess()
Definition: miscadmin.h:381
#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:81
Relation index
Definition: genam.h:48
BufferAccessStrategy strategy
Definition: genam.h:55
static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)
Definition: test_ifaddrs.c:46
void vacuum_delay_point(void)
Definition: vacuum.c:2361

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

Referenced by ginhandler().

◆ ginCompareAttEntries()

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

Definition at line 411 of file ginutil.c.

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

References a, b, and ginCompareEntries().

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

◆ ginCompareEntries()

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

Definition at line 389 of file ginutil.c.

392{
393 /* if not of same null category, sort by that first */
394 if (categorya != categoryb)
395 return (categorya < categoryb) ? -1 : 1;
396
397 /* all null items in same category are equal */
398 if (categorya != GIN_CAT_NORM_KEY)
399 return 0;
400
401 /* both not null, so safe to call the compareFn */
402 return DatumGetInt32(FunctionCall2Coll(&ginstate->compareFn[attnum - 1],
403 ginstate->supportCollation[attnum - 1],
404 a, b));
405}
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1149
#define GIN_CAT_NORM_KEY
Definition: ginblock.h:208
static int32 DatumGetInt32(Datum X)
Definition: postgres.h: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(), 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:776
#define SHORTALIGN(LEN)
Definition: c.h:764
static uint64 itemptr_to_uint64(const ItemPointer iptr)
static void encode_varbyte(uint64 val, unsigned char **ptr)
ItemPointer ginPostingListDecode(GinPostingList *plist, int *ndecoded_out)
#define MaxBytesPerInteger
long val
Definition: informix.c:689
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:76
static char * buf
Definition: pg_test_fsync.c:72
ItemPointerData first
Definition: ginblock.h:337
unsigned char bytes[FLEXIBLE_ARRAY_MEMBER]
Definition: ginblock.h:339
uint16 nbytes
Definition: ginblock.h:338

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

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

◆ ginDataFillRoot()

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

Definition at line 1349 of file gindatapage.c.

1350{
1351 PostingItem li,
1352 ri;
1353
1354 li.key = *GinDataPageGetRightBound(lpage);
1355 PostingItemSetBlockNumber(&li, lblkno);
1357
1358 ri.key = *GinDataPageGetRightBound(rpage);
1359 PostingItemSetBlockNumber(&ri, rblkno);
1361}
#define GinDataPageGetRightBound(page)
Definition: ginblock.h:288
#define PostingItemSetBlockNumber(pointer, blockNumber)
Definition: ginblock.h:192
void GinDataPageAddPostingItem(Page page, PostingItem *data, OffsetNumber offset)
Definition: gindatapage.c:380
#define InvalidOffsetNumber
Definition: off.h:26
tree ctl root
Definition: radixtree.h: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:219
size_t Size
Definition: c.h:562
static int ginCompareItemPointers(ItemPointer a, ItemPointer b)
Definition: gin_private.h:488
#define GinDataLeafPageGetPostingListSize(page)
Definition: ginblock.h:280
#define GinNextPostingListSegment(cur)
Definition: ginblock.h:343
#define GinPageIsCompressed(page)
Definition: ginblock.h:121
static ItemPointer dataLeafPageGetUncompressed(Page page, int *nitems)
Definition: gindatapage.c:211
ItemPointer ginPostingListDecodeAllSegments(GinPostingList *segment, int len, int *ndecoded_out)
static bool ItemPointerIsValid(const ItemPointerData *pointer)
Definition: itemptr.h:83
const void size_t len

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

Referenced by entryLoadMoreItems(), and startScanEntry().

◆ GinDataLeafPageGetItemsToTbm()

int GinDataLeafPageGetItemsToTbm ( Page  page,
TIDBitmap tbm 
)

Definition at line 182 of file gindatapage.c.

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

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

Referenced by scanPostingTree().

◆ GinDataPageAddPostingItem()

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

Definition at line 380 of file gindatapage.c.

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

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

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

◆ ginendscan()

void ginendscan ( IndexScanDesc  scan)

Definition at line 455 of file ginscan.c.

456{
458
459 ginFreeScanKeys(so);
460
463
464 pfree(so);
465}
void ginFreeScanKeys(GinScanOpaque so)
Definition: ginscan.c:233

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

Referenced by ginhandler().

◆ ginEntryFillRoot()

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

Definition at line 723 of file ginentrypage.c.

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

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

Referenced by ginPrepareEntryScan().

◆ ginEntryInsert()

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

Definition at line 176 of file gininsert.c.

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

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

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

◆ ginExtractEntries()

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

Definition at line 484 of file ginutil.c.

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

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

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

◆ ginFindLeafPage()

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

Definition at line 83 of file ginbtree.c.

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

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

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

◆ GinFormTuple()

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

Definition at line 44 of file ginentrypage.c.

48{
49 Datum datums[2];
50 bool isnull[2];
51 IndexTuple itup;
52 uint32 newsize;
53
54 /* Build the basic tuple: optional column number, plus key datum */
55 if (ginstate->oneCol)
56 {
57 datums[0] = key;
58 isnull[0] = (category != GIN_CAT_NORM_KEY);
59 }
60 else
61 {
62 datums[0] = UInt16GetDatum(attnum);
63 isnull[0] = false;
64 datums[1] = key;
65 isnull[1] = (category != GIN_CAT_NORM_KEY);
66 }
67
68 itup = index_form_tuple(ginstate->tupdesc[attnum - 1], datums, isnull);
69
70 /*
71 * Determine and store offset to the posting list, making sure there is
72 * room for the category byte if needed.
73 *
74 * Note: because index_form_tuple MAXALIGNs the tuple size, there may well
75 * be some wasted pad space. Is it worth recomputing the data length to
76 * prevent that? That would also allow us to Assert that the real data
77 * doesn't overlap the GinNullCategory byte, which this code currently
78 * takes on faith.
79 */
80 newsize = IndexTupleSize(itup);
81
82 if (IndexTupleHasNulls(itup))
83 {
84 uint32 minsize;
85
86 Assert(category != GIN_CAT_NORM_KEY);
87 minsize = GinCategoryOffset(itup, ginstate) + sizeof(GinNullCategory);
88 newsize = Max(newsize, minsize);
89 }
90
91 newsize = SHORTALIGN(newsize);
92
93 GinSetPostingOffset(itup, newsize);
94 GinSetNPosting(itup, nipd);
95
96 /*
97 * Add space needed for posting list, if any. Then check that the tuple
98 * won't be too big to store.
99 */
100 newsize += dataSize;
101
102 newsize = MAXALIGN(newsize);
103
104 if (newsize > GinMaxItemSize)
105 {
106 if (errorTooBig)
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:768
#define Max(x, y)
Definition: c.h:955
#define GinCategoryOffset(itup, ginstate)
Definition: ginblock.h:217
#define GinGetPosting(itup)
Definition: ginblock.h:238
#define GinSetNPosting(itup, n)
Definition: ginblock.h:229
#define GinSetPostingOffset(itup, n)
Definition: ginblock.h:237
#define GinSetNullCategory(itup, ginstate, c)
Definition: ginblock.h:222
#define GinMaxItemSize
Definition: ginblock.h:248
IndexTuple index_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: indextuple.c:44
#define IndexTupleHasNulls(itup)
Definition: itup.h:71
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1541
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 233 of file ginscan.c.

234{
235 uint32 i;
236
237 if (so->keys == NULL)
238 return;
239
240 for (i = 0; i < so->totalentries; i++)
241 {
242 GinScanEntry entry = so->entries[i];
243
244 if (entry->buffer != InvalidBuffer)
245 ReleaseBuffer(entry->buffer);
246 if (entry->list)
247 pfree(entry->list);
248 if (entry->matchIterator)
250 if (entry->matchBitmap)
251 tbm_free(entry->matchBitmap);
252 }
253
255
256 so->keys = NULL;
257 so->nkeys = 0;
258 so->entries = NULL;
259 so->totalentries = 0;
260}
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:383
TIDBitmap * matchBitmap
Definition: gin_private.h:354
ItemPointerData * list
Definition: gin_private.h:359
TBMPrivateIterator * matchIterator
Definition: gin_private.h:355
GinScanEntry * entries
Definition: gin_private.h:377
void tbm_free(TIDBitmap *tbm)
Definition: tidbitmap.c:322
void tbm_end_private_iterate(TBMPrivateIterator *iterator)
Definition: tidbitmap.c:1147

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:474
RBTNode * rbt_iterate(RBTreeIterator *iter)
Definition: rbtree.c:826
OffsetNumber attnum
Definition: gin_private.h:424
ItemPointerData * list
Definition: gin_private.h:426
GinNullCategory category
Definition: gin_private.h:423

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

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

◆ gingetbitmap()

int64 gingetbitmap ( IndexScanDesc  scan,
TIDBitmap tbm 
)

Definition at line 1916 of file ginget.c.

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

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

Referenced by ginhandler().

◆ ginHeapTupleFastCollect()

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

Definition at line 483 of file ginfast.c.

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

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

Referenced by gininsert().

◆ ginHeapTupleFastInsert()

void ginHeapTupleFastInsert ( GinState ginstate,
GinTupleCollector collector 
)

Definition at line 219 of file ginfast.c.

220{
221 Relation index = ginstate->index;
222 Buffer metabuffer;
223 Page metapage;
224 GinMetaPageData *metadata = NULL;
225 Buffer buffer = InvalidBuffer;
226 Page page = NULL;
228 bool separateList = false;
229 bool needCleanup = false;
230 int cleanupSize;
231 bool needWal;
232
233 if (collector->ntuples == 0)
234 return;
235
236 needWal = RelationNeedsWAL(index);
237
238 data.locator = index->rd_locator;
239 data.ntuples = 0;
240 data.newRightlink = data.prevTail = InvalidBlockNumber;
241
242 metabuffer = ReadBuffer(index, GIN_METAPAGE_BLKNO);
243 metapage = BufferGetPage(metabuffer);
244
245 /*
246 * An insertion to the pending list could logically belong anywhere in the
247 * tree, so it conflicts with all serializable scans. All scans acquire a
248 * predicate lock on the metabuffer to represent that. Therefore we'll
249 * check for conflicts in, but not until we have the page locked and are
250 * ready to modify the page.
251 */
252
253 if (collector->sumsize + collector->ntuples * sizeof(ItemIdData) > GinListPageSize)
254 {
255 /*
256 * Total size is greater than one page => make sublist
257 */
258 separateList = true;
259 }
260 else
261 {
262 LockBuffer(metabuffer, GIN_EXCLUSIVE);
263 metadata = GinPageGetMeta(metapage);
264
265 if (metadata->head == InvalidBlockNumber ||
266 collector->sumsize + collector->ntuples * sizeof(ItemIdData) > metadata->tailFreeSize)
267 {
268 /*
269 * Pending list is empty or total size is greater than freespace
270 * on tail page => make sublist
271 *
272 * We unlock metabuffer to keep high concurrency
273 */
274 separateList = true;
275 LockBuffer(metabuffer, GIN_UNLOCK);
276 }
277 }
278
279 if (separateList)
280 {
281 /*
282 * We should make sublist separately and append it to the tail
283 */
284 GinMetaPageData sublist;
285
286 memset(&sublist, 0, sizeof(GinMetaPageData));
287 makeSublist(index, collector->tuples, collector->ntuples, &sublist);
288
289 /*
290 * metapage was unlocked, see above
291 */
292 LockBuffer(metabuffer, GIN_EXCLUSIVE);
293 metadata = GinPageGetMeta(metapage);
294
296
297 if (metadata->head == InvalidBlockNumber)
298 {
299 /*
300 * Main list is empty, so just insert sublist as main list
301 */
303
304 metadata->head = sublist.head;
305 metadata->tail = sublist.tail;
306 metadata->tailFreeSize = sublist.tailFreeSize;
307
308 metadata->nPendingPages = sublist.nPendingPages;
309 metadata->nPendingHeapTuples = sublist.nPendingHeapTuples;
310
311 if (needWal)
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
434 XLogRegisterData((char *) &data, sizeof(ginxlogUpdateMeta));
435
436 recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_UPDATE_META_PAGE);
437 PageSetLSN(metapage, recptr);
438
439 if (buffer != InvalidBuffer)
440 {
441 PageSetLSN(page, recptr);
442 }
443 }
444
445 if (buffer != InvalidBuffer)
446 UnlockReleaseBuffer(buffer);
447
448 /*
449 * Force pending list cleanup when it becomes too long. And,
450 * ginInsertCleanup could take significant amount of time, so we prefer to
451 * call it when it can do all the work in a single collection cycle. In
452 * non-vacuum mode, it shouldn't require maintenance_work_mem, so fire it
453 * while pending list is still small enough to fit into
454 * gin_pending_list_limit.
455 *
456 * ginInsertCleanup() should not be called inside our CRIT_SECTION.
457 */
458 cleanupSize = GinGetPendingListCleanupSize(index);
459 if (metadata->nPendingPages * GIN_PAGE_FREESIZE > cleanupSize * 1024L)
460 needCleanup = true;
461
462 UnlockReleaseBuffer(metabuffer);
463
465
466 /*
467 * Since it could contend with concurrent cleanup process we cleanup
468 * pending list not forcibly.
469 */
470 if (needCleanup)
471 ginInsertCleanup(ginstate, false, true, false, NULL);
472}
Size PageGetExactFreeSpace(Page page)
Definition: bufpage.c:947
PageHeaderData * PageHeader
Definition: bufpage.h:173
static bool PageIsEmpty(Page page)
Definition: bufpage.h:223
#define GinGetPendingListCleanupSize(relation)
Definition: gin_private.h:39
#define GinListPageSize
Definition: ginblock.h:327
#define GIN_METAPAGE_BLKNO
Definition: ginblock.h:51
#define GinPageGetMeta(p)
Definition: ginblock.h:104
#define GIN_PAGE_FREESIZE
Definition: ginfast.c:41
static void makeSublist(Relation index, IndexTuple *tuples, int32 ntuples, GinMetaPageData *res)
Definition: ginfast.c:145
#define XLOG_GIN_UPDATE_META_PAGE
Definition: ginxlog.h:162
#define OffsetNumberNext(offsetNumber)
Definition: off.h:52
BlockNumber tail
Definition: ginblock.h:62
uint32 tailFreeSize
Definition: ginblock.h:67
BlockNumber nPendingPages
Definition: ginblock.h:73
int64 nPendingHeapTuples
Definition: ginblock.h:74
BlockNumber head
Definition: ginblock.h:61
void XLogRegisterBufData(uint8 block_id, const char *data, uint32 len)
Definition: xloginsert.c:405
#define REGBUF_STANDARD
Definition: xloginsert.h:34

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

Referenced by gininsert().

◆ ginInitBA()

void ginInitBA ( BuildAccumulator accum)

Definition at line 109 of file ginbulk.c.

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

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

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

◆ GinInitBuffer()

void GinInitBuffer ( Buffer  b,
uint32  f 
)

Definition at line 351 of file ginutil.c.

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

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

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

◆ ginInitConsistentFunction()

void ginInitConsistentFunction ( GinState ginstate,
GinScanKey  key 
)

Definition at line 217 of file ginlogic.c.

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

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

Referenced by ginFillScanKey().

◆ GinInitMetabuffer()

void GinInitMetabuffer ( Buffer  b)

Definition at line 357 of file ginutil.c.

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

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

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

◆ GinInitPage()

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

Definition at line 339 of file ginutil.c.

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

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

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

◆ gininsert()

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

Definition at line 482 of file gininsert.c.

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

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

Referenced by ginhandler().

◆ ginInsertBAEntries()

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

Definition at line 210 of file ginbulk.c.

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

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

Referenced by ginHeapTupleBulkInsert(), and processPendingPage().

◆ ginInsertCleanup()

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

Definition at line 780 of file ginfast.c.

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

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

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

◆ ginInsertItemPointers()

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

Definition at line 1908 of file gindatapage.c.

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

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

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

◆ ginInsertValue()

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

Definition at line 816 of file ginbtree.c.

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

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

Referenced by ginEntryInsert(), and ginInsertItemPointers().

◆ ginMergeItemPointers()

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

Definition at line 378 of file ginpostinglist.c.

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

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

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

◆ GinNewBuffer()

Buffer GinNewBuffer ( Relation  index)

Definition at line 301 of file ginutil.c.

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

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

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

◆ ginNewScanKey()

void ginNewScanKey ( IndexScanDesc  scan)

Definition at line 263 of file ginscan.c.

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

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

Referenced by gingetbitmap().

◆ ginoptions()

bytea * ginoptions ( Datum  reloptions,
bool  validate 
)

Definition at line 603 of file ginutil.c.

604{
605 static const relopt_parse_elt tab[] = {
606 {"fastupdate", RELOPT_TYPE_BOOL, offsetof(GinOptions, useFastUpdate)},
607 {"gin_pending_list_limit", RELOPT_TYPE_INT, offsetof(GinOptions,
608 pendingListCleanupSize)}
609 };
610
611 return (bytea *) build_reloptions(reloptions, validate,
613 sizeof(GinOptions),
614 tab, lengthof(tab));
615}
#define lengthof(array)
Definition: c.h:745
void * build_reloptions(Datum reloptions, bool validate, relopt_kind kind, Size relopt_struct_size, const relopt_parse_elt *relopt_elems, int num_relopt_elems)
Definition: reloptions.c:1908
@ RELOPT_KIND_GIN
Definition: reloptions.h:46
@ RELOPT_TYPE_INT
Definition: reloptions.h:32
@ RELOPT_TYPE_BOOL
Definition: reloptions.h:31
Definition: c.h:644

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

Referenced by ginhandler().

◆ GinPageDeletePostingItem()

void GinPageDeletePostingItem ( Page  page,
OffsetNumber  offset 
)

Definition at line 417 of file gindatapage.c.

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

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

Referenced by ginDeletePage(), and ginRedoDeletePage().

◆ ginPostingListDecode()

◆ ginPostingListDecodeAllSegments()

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

Definition at line 297 of file ginpostinglist.c.

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

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

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

◆ ginPostingListDecodeAllSegmentsToTbm()

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

Definition at line 358 of file ginpostinglist.c.

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

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

Referenced by GinDataLeafPageGetItemsToTbm().

◆ ginPrepareEntryScan()

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

Definition at line 747 of file ginentrypage.c.

750{
751 memset(btree, 0, sizeof(GinBtreeData));
752
753 btree->index = ginstate->index;
754 btree->rootBlkno = GIN_ROOT_BLKNO;
755 btree->ginstate = ginstate;
756
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:175
GinState * ginstate
Definition: gin_private.h:169
void(* execPlaceToPage)(GinBtree, Buffer, GinBtreeStack *, void *, BlockNumber, void *)
Definition: gin_private.h:161
BlockNumber(* getLeftMostChild)(GinBtree, Page)
Definition: gin_private.h:154
void *(* prepareDownlink)(GinBtree, Buffer)
Definition: gin_private.h:162
GinPlaceToPageRC(* beginPlaceToPage)(GinBtree, Buffer, GinBtreeStack *, void *, BlockNumber, void **, Page *, Page *)
Definition: gin_private.h:160
GinNullCategory entryCategory
Definition: gin_private.h:176
OffsetNumber entryAttnum
Definition: gin_private.h:174
OffsetNumber(* findChildPtr)(GinBtree, Page, BlockNumber, OffsetNumber)
Definition: gin_private.h:159
void(* fillRoot)(GinBtree, Page, BlockNumber, Page, BlockNumber, Page)
Definition: gin_private.h:163

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

Referenced by ginEntryInsert(), and startScanEntry().

◆ ginReadTuple()

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

Definition at line 162 of file ginentrypage.c.

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

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

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

◆ ginrescan()

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

Definition at line 442 of file ginscan.c.

444{
446
447 ginFreeScanKeys(so);
448
449 if (scankey && scan->numberOfKeys > 0)
450 memcpy(scan->keyData, scankey, scan->numberOfKeys * sizeof(ScanKeyData));
451}

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

Referenced by ginhandler().

◆ ginScanBeginPostingTree()

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

Definition at line 1936 of file gindatapage.c.

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

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

Referenced by scanPostingTree(), and startScanEntry().

◆ ginStepRight()

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

Definition at line 177 of file ginbtree.c.

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

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

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

◆ ginTraverseLock()

int ginTraverseLock ( Buffer  buffer,
bool  searchMode 
)

Definition at line 39 of file ginbtree.c.

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

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

Referenced by ginFindLeafPage().

◆ gintuple_get_attrnum()

OffsetNumber gintuple_get_attrnum ( GinState ginstate,
IndexTuple  tuple 
)

Definition at line 227 of file ginutil.c.

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

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

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

◆ gintuple_get_key()

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

Definition at line 260 of file ginutil.c.

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

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

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

◆ ginvacuumcleanup()

IndexBulkDeleteResult * ginvacuumcleanup ( IndexVacuumInfo info,
IndexBulkDeleteResult stats 
)

Definition at line 687 of file ginvacuum.c.

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

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

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

Referenced by ginhandler().

◆ initGinState()

void initGinState ( GinState state,
Relation  index 
)

Definition at line 98 of file ginutil.c.

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

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

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