#include "access/genam.h"
#include "access/gin.h"
#include "access/itup.h"
#include "fmgr.h"
#include "storage/bufmgr.h"
#include "utils/rbtree.h"
Go to the source code of this file.
Data Structures | |
struct | GinPageOpaqueData |
struct | GinMetaPageData |
struct | PostingItem |
struct | GinOptions |
struct | GinState |
struct | ginxlogCreatePostingTree |
struct | ginxlogInsert |
struct | ginxlogSplit |
struct | ginxlogVacuumPage |
struct | ginxlogDeletePage |
struct | ginxlogUpdateMeta |
struct | ginxlogInsertListPage |
struct | ginxlogDeleteListPages |
struct | GinBtreeStack |
struct | GinBtreeData |
struct | GinPostingTreeScan |
struct | GinScanKeyData |
struct | GinScanEntryData |
struct | GinScanOpaqueData |
struct | GinEntryAccumulator |
struct | BuildAccumulator |
struct | GinTupleCollector |
Defines | |
#define | GIN_DATA (1 << 0) |
#define | GIN_LEAF (1 << 1) |
#define | GIN_DELETED (1 << 2) |
#define | GIN_META (1 << 3) |
#define | GIN_LIST (1 << 4) |
#define | GIN_LIST_FULLROW (1 << 5) |
#define | GIN_METAPAGE_BLKNO (0) |
#define | GIN_ROOT_BLKNO (1) |
#define | GIN_CURRENT_VERSION 1 |
#define | GinPageGetMeta(p) ((GinMetaPageData *) PageGetContents(p)) |
#define | GinPageGetOpaque(page) ( (GinPageOpaque) PageGetSpecialPointer(page) ) |
#define | GinPageIsLeaf(page) ( GinPageGetOpaque(page)->flags & GIN_LEAF ) |
#define | GinPageSetLeaf(page) ( GinPageGetOpaque(page)->flags |= GIN_LEAF ) |
#define | GinPageSetNonLeaf(page) ( GinPageGetOpaque(page)->flags &= ~GIN_LEAF ) |
#define | GinPageIsData(page) ( GinPageGetOpaque(page)->flags & GIN_DATA ) |
#define | GinPageSetData(page) ( GinPageGetOpaque(page)->flags |= GIN_DATA ) |
#define | GinPageIsList(page) ( GinPageGetOpaque(page)->flags & GIN_LIST ) |
#define | GinPageSetList(page) ( GinPageGetOpaque(page)->flags |= GIN_LIST ) |
#define | GinPageHasFullRow(page) ( GinPageGetOpaque(page)->flags & GIN_LIST_FULLROW ) |
#define | GinPageSetFullRow(page) ( GinPageGetOpaque(page)->flags |= GIN_LIST_FULLROW ) |
#define | GinPageIsDeleted(page) ( GinPageGetOpaque(page)->flags & GIN_DELETED) |
#define | GinPageSetDeleted(page) ( GinPageGetOpaque(page)->flags |= GIN_DELETED) |
#define | GinPageSetNonDeleted(page) ( GinPageGetOpaque(page)->flags &= ~GIN_DELETED) |
#define | GinPageRightMost(page) ( GinPageGetOpaque(page)->rightlink == InvalidBlockNumber) |
#define | GinItemPointerGetBlockNumber(pointer) BlockIdGetBlockNumber(&(pointer)->ip_blkid) |
#define | GinItemPointerGetOffsetNumber(pointer) ((pointer)->ip_posid) |
#define | ItemPointerSetMin(p) ItemPointerSet((p), (BlockNumber)0, (OffsetNumber)0) |
#define | ItemPointerIsMin(p) |
#define | ItemPointerSetMax(p) ItemPointerSet((p), InvalidBlockNumber, (OffsetNumber)0xffff) |
#define | ItemPointerIsMax(p) |
#define | ItemPointerSetLossyPage(p, b) ItemPointerSet((p), (b), (OffsetNumber)0xffff) |
#define | ItemPointerIsLossyPage(p) |
#define | PostingItemGetBlockNumber(pointer) BlockIdGetBlockNumber(&(pointer)->child_blkno) |
#define | PostingItemSetBlockNumber(pointer, blockNumber) BlockIdSet(&((pointer)->child_blkno), (blockNumber)) |
#define | GIN_CAT_NORM_KEY 0 |
#define | GIN_CAT_NULL_KEY 1 |
#define | GIN_CAT_EMPTY_ITEM 2 |
#define | GIN_CAT_NULL_ITEM 3 |
#define | GIN_CAT_EMPTY_QUERY (-1) |
#define | GinCategoryOffset(itup, ginstate) |
#define | GinGetNullCategory(itup, ginstate) (*((GinNullCategory *) ((char*)(itup) + GinCategoryOffset(itup,ginstate)))) |
#define | GinSetNullCategory(itup, ginstate, c) (*((GinNullCategory *) ((char*)(itup) + GinCategoryOffset(itup,ginstate))) = (c)) |
#define | GinGetNPosting(itup) GinItemPointerGetOffsetNumber(&(itup)->t_tid) |
#define | GinSetNPosting(itup, n) ItemPointerSetOffsetNumber(&(itup)->t_tid,n) |
#define | GIN_TREE_POSTING ((OffsetNumber)0xffff) |
#define | GinIsPostingTree(itup) (GinGetNPosting(itup) == GIN_TREE_POSTING) |
#define | GinSetPostingTree(itup, blkno) ( GinSetNPosting((itup),GIN_TREE_POSTING), ItemPointerSetBlockNumber(&(itup)->t_tid, blkno) ) |
#define | GinGetPostingTree(itup) GinItemPointerGetBlockNumber(&(itup)->t_tid) |
#define | GinGetPostingOffset(itup) GinItemPointerGetBlockNumber(&(itup)->t_tid) |
#define | GinSetPostingOffset(itup, n) ItemPointerSetBlockNumber(&(itup)->t_tid,n) |
#define | GinGetPosting(itup) ((ItemPointer) ((char*)(itup) + GinGetPostingOffset(itup))) |
#define | GinMaxItemSize |
#define | GinGetDownlink(itup) GinItemPointerGetBlockNumber(&(itup)->t_tid) |
#define | GinSetDownlink(itup, blkno) ItemPointerSet(&(itup)->t_tid, blkno, InvalidOffsetNumber) |
#define | GinDataPageGetRightBound(page) ((ItemPointer) PageGetContents(page)) |
#define | GinDataPageGetData(page) (PageGetContents(page) + MAXALIGN(sizeof(ItemPointerData))) |
#define | GinSizeOfDataPageItem(page) (GinPageIsLeaf(page) ? sizeof(ItemPointerData) : sizeof(PostingItem)) |
#define | GinDataPageGetItem(page, i) (GinDataPageGetData(page) + ((i)-1) * GinSizeOfDataPageItem(page)) |
#define | GinDataPageGetFreeSpace(page) |
#define | GinMaxLeafDataItems |
#define | GinListPageSize ( BLCKSZ - SizeOfPageHeaderData - MAXALIGN(sizeof(GinPageOpaqueData)) ) |
#define | GIN_DEFAULT_USE_FASTUPDATE true |
#define | GinGetUseFastUpdate(relation) |
#define | GIN_UNLOCK BUFFER_LOCK_UNLOCK |
#define | GIN_SHARE BUFFER_LOCK_SHARE |
#define | GIN_EXCLUSIVE BUFFER_LOCK_EXCLUSIVE |
#define | XLOG_GIN_CREATE_INDEX 0x00 |
#define | XLOG_GIN_CREATE_PTREE 0x10 |
#define | XLOG_GIN_INSERT 0x20 |
#define | XLOG_GIN_SPLIT 0x30 |
#define | XLOG_GIN_VACUUM_PAGE 0x40 |
#define | XLOG_GIN_DELETE_PAGE 0x50 |
#define | XLOG_GIN_UPDATE_META_PAGE 0x60 |
#define | XLOG_GIN_INSERT_LISTPAGE 0x70 |
#define | XLOG_GIN_DELETE_LISTPAGE 0x80 |
#define | GIN_NDELETE_AT_ONCE 16 |
Typedefs | |
typedef struct GinPageOpaqueData | GinPageOpaqueData |
typedef GinPageOpaqueData * | GinPageOpaque |
typedef struct GinMetaPageData | GinMetaPageData |
typedef signed char | GinNullCategory |
typedef struct GinOptions | GinOptions |
typedef struct GinState | GinState |
typedef struct ginxlogCreatePostingTree | ginxlogCreatePostingTree |
typedef struct ginxlogInsert | ginxlogInsert |
typedef struct ginxlogSplit | ginxlogSplit |
typedef struct ginxlogVacuumPage | ginxlogVacuumPage |
typedef struct ginxlogDeletePage | ginxlogDeletePage |
typedef struct ginxlogUpdateMeta | ginxlogUpdateMeta |
typedef struct ginxlogInsertListPage | ginxlogInsertListPage |
typedef struct ginxlogDeleteListPages | ginxlogDeleteListPages |
typedef struct GinBtreeStack | GinBtreeStack |
typedef struct GinBtreeData * | GinBtree |
typedef struct GinBtreeData | GinBtreeData |
typedef struct GinScanKeyData * | GinScanKey |
typedef struct GinScanEntryData * | GinScanEntry |
typedef struct GinScanKeyData | GinScanKeyData |
typedef struct GinScanEntryData | GinScanEntryData |
typedef struct GinScanOpaqueData | GinScanOpaqueData |
typedef GinScanOpaqueData * | GinScanOpaque |
typedef struct GinEntryAccumulator | GinEntryAccumulator |
typedef struct GinTupleCollector | GinTupleCollector |
Functions | |
Datum | ginoptions (PG_FUNCTION_ARGS) |
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) |
Datum * | ginExtractEntries (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) |
Datum | ginbuild (PG_FUNCTION_ARGS) |
Datum | ginbuildempty (PG_FUNCTION_ARGS) |
Datum | gininsert (PG_FUNCTION_ARGS) |
void | ginEntryInsert (GinState *ginstate, OffsetNumber attnum, Datum key, GinNullCategory category, ItemPointerData *items, uint32 nitem, GinStatsData *buildStats) |
GinBtreeStack * | ginPrepareFindLeafPage (GinBtree btree, BlockNumber blkno) |
GinBtreeStack * | ginFindLeafPage (GinBtree btree, GinBtreeStack *stack) |
void | freeGinBtreeStack (GinBtreeStack *stack) |
void | ginInsertValue (GinBtree btree, GinBtreeStack *stack, GinStatsData *buildStats) |
void | ginFindParents (GinBtree btree, GinBtreeStack *stack, BlockNumber rootBlkno) |
IndexTuple | GinFormTuple (GinState *ginstate, OffsetNumber attnum, Datum key, GinNullCategory category, ItemPointerData *ipd, uint32 nipd, bool errorTooBig) |
void | GinShortenTuple (IndexTuple itup, uint32 nipd) |
void | ginPrepareEntryScan (GinBtree btree, OffsetNumber attnum, Datum key, GinNullCategory category, GinState *ginstate) |
void | ginEntryFillRoot (GinBtree btree, Buffer root, Buffer lbuf, Buffer rbuf) |
IndexTuple | ginPageGetLinkItup (Buffer buf) |
int | ginCompareItemPointers (ItemPointer a, ItemPointer b) |
uint32 | ginMergeItemPointers (ItemPointerData *dst, ItemPointerData *a, uint32 na, ItemPointerData *b, uint32 nb) |
void | GinDataPageAddItem (Page page, void *data, OffsetNumber offset) |
void | GinPageDeletePostingItem (Page page, OffsetNumber offset) |
GinPostingTreeScan * | ginPrepareScanPostingTree (Relation index, BlockNumber rootBlkno, bool searchMode) |
void | ginInsertItemPointers (GinPostingTreeScan *gdi, ItemPointerData *items, uint32 nitem, GinStatsData *buildStats) |
Buffer | ginScanBeginPostingTree (GinPostingTreeScan *gdi) |
void | ginDataFillRoot (GinBtree btree, Buffer root, Buffer lbuf, Buffer rbuf) |
void | ginPrepareDataScan (GinBtree btree, Relation index) |
Datum | ginbeginscan (PG_FUNCTION_ARGS) |
Datum | ginendscan (PG_FUNCTION_ARGS) |
Datum | ginrescan (PG_FUNCTION_ARGS) |
Datum | ginmarkpos (PG_FUNCTION_ARGS) |
Datum | ginrestrpos (PG_FUNCTION_ARGS) |
void | ginNewScanKey (IndexScanDesc scan) |
Datum | gingetbitmap (PG_FUNCTION_ARGS) |
Datum | ginbulkdelete (PG_FUNCTION_ARGS) |
Datum | ginvacuumcleanup (PG_FUNCTION_ARGS) |
void | ginInitBA (BuildAccumulator *accum) |
void | ginInsertBAEntries (BuildAccumulator *accum, ItemPointer heapptr, OffsetNumber attnum, Datum *entries, GinNullCategory *categories, int32 nentries) |
void | ginBeginBAScan (BuildAccumulator *accum) |
ItemPointerData * | ginGetBAEntry (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 vac_delay, IndexBulkDeleteResult *stats) |
#define GIN_CAT_EMPTY_ITEM 2 |
Definition at line 189 of file gin_private.h.
#define GIN_CAT_EMPTY_QUERY (-1) |
Definition at line 191 of file gin_private.h.
Referenced by collectMatchesForHeapRow(), and startScanEntry().
#define GIN_CAT_NORM_KEY 0 |
Definition at line 187 of file gin_private.h.
Referenced by collectMatchBitmap(), ginCompareEntries(), GinFormTuple(), ginInsertBAEntry(), and matchPartialInPendingList().
#define GIN_CAT_NULL_ITEM 3 |
Definition at line 190 of file gin_private.h.
Referenced by collectMatchBitmap(), and collectMatchesForHeapRow().
#define GIN_CAT_NULL_KEY 1 |
Definition at line 188 of file gin_private.h.
Referenced by ginContinueSplit().
#define GIN_CURRENT_VERSION 1 |
Definition at line 99 of file gin_private.h.
#define GIN_DATA (1 << 0) |
Definition at line 45 of file gin_private.h.
Referenced by createPostingTree(), and ginRedoCreatePTree().
#define GIN_DEFAULT_USE_FASTUPDATE true |
Definition at line 267 of file gin_private.h.
#define GIN_DELETED (1 << 2) |
Definition at line 47 of file gin_private.h.
Referenced by findItemInPostingPage(), and scanPostingTree().
#define GIN_EXCLUSIVE BUFFER_LOCK_EXCLUSIVE |
Definition at line 276 of file gin_private.h.
Referenced by ginbulkdelete(), ginDeletePage(), ginFindParents(), ginHeapTupleFastInsert(), ginInsertCleanup(), ginInsertValue(), GinNewBuffer(), ginTraverseLock(), ginUpdateStats(), ginVacuumPostingTreeLeaves(), and shiftList().
#define GIN_LEAF (1 << 1) |
Definition at line 46 of file gin_private.h.
Referenced by createPostingTree(), ginbuild(), ginbuildempty(), ginInsertValue(), ginRedoCreateIndex(), ginRedoCreatePTree(), and ginRedoSplit().
#define GIN_LIST (1 << 4) |
Definition at line 49 of file gin_private.h.
Referenced by ginRedoInsertListPage(), and writeListPage().
#define GIN_LIST_FULLROW (1 << 5) |
Definition at line 50 of file gin_private.h.
#define GIN_META (1 << 3) |
Definition at line 48 of file gin_private.h.
Referenced by GinInitMetabuffer().
#define GIN_METAPAGE_BLKNO (0) |
Definition at line 53 of file gin_private.h.
Referenced by gin_desc(), ginGetStats(), ginHeapTupleFastInsert(), ginInsertCleanup(), ginRedoCreateIndex(), ginRedoDeleteListPages(), ginRedoUpdateMetapage(), ginUpdateStats(), pgstatginindex(), and scanPendingInsert().
#define GIN_NDELETE_AT_ONCE 16 |
Definition at line 420 of file gin_private.h.
Referenced by shiftList().
#define GIN_ROOT_BLKNO (1) |
Definition at line 54 of file gin_private.h.
Referenced by entryLocateEntry(), gin_desc(), ginbulkdelete(), ginContinueSplit(), ginFindLeafPage(), ginRedoCreateIndex(), ginRedoSplit(), and ginvacuumcleanup().
#define GIN_SHARE BUFFER_LOCK_SHARE |
Definition at line 275 of file gin_private.h.
Referenced by collectMatchBitmap(), entryGetNextItem(), ginbulkdelete(), ginGetStats(), ginInsertCleanup(), ginTraverseLock(), ginvacuumcleanup(), moveRightIfItNeeded(), pgstatginindex(), scanGetCandidate(), scanPendingInsert(), and scanPostingTree().
#define GIN_TREE_POSTING ((OffsetNumber)0xffff) |
Definition at line 209 of file gin_private.h.
#define GIN_UNLOCK BUFFER_LOCK_UNLOCK |
Definition at line 274 of file gin_private.h.
Referenced by collectMatchBitmap(), entryGetNextItem(), ginbulkdelete(), ginDeletePage(), ginEntryInsert(), ginFindLeafPage(), ginFindParents(), ginHeapTupleFastInsert(), ginInsertCleanup(), ginInsertItemPointers(), ginInsertValue(), GinNewBuffer(), ginTraverseLock(), moveRightIfItNeeded(), scanPostingTree(), and startScanEntry().
#define GinCategoryOffset | ( | itup, | ||
ginstate | ||||
) |
(IndexInfoFindDataOffset((itup)->t_info) + \ ((ginstate)->oneCol ? 0 : sizeof(int16)))
Definition at line 196 of file gin_private.h.
Referenced by GinFormTuple().
#define GinDataPageGetData | ( | page | ) | (PageGetContents(page) + MAXALIGN(sizeof(ItemPointerData))) |
Definition at line 233 of file gin_private.h.
Referenced by createPostingTree(), ginRedoCreatePTree(), ginRedoVacuumPage(), ginVacuumPostingTreeLeaves(), and xlogVacuumPage().
#define GinDataPageGetFreeSpace | ( | page | ) |
(BLCKSZ - MAXALIGN(SizeOfPageHeaderData) \ - MAXALIGN(sizeof(ItemPointerData)) \ - GinPageGetOpaque(page)->maxoff * GinSizeOfDataPageItem(page) \ - MAXALIGN(sizeof(GinPageOpaqueData)))
Definition at line 240 of file gin_private.h.
Referenced by dataIsEnoughSpace(), and dataSplitPage().
#define GinDataPageGetItem | ( | page, | ||
i | ||||
) | (GinDataPageGetData(page) + ((i)-1) * GinSizeOfDataPageItem(page)) |
Definition at line 237 of file gin_private.h.
Referenced by dataFindChildPtr(), dataGetLeftMostPage(), dataLocateItem(), dataLocateLeafItem(), dataPrepareData(), dataSplitPage(), entryGetNextItem(), findItemInPostingPage(), ginContinueSplit(), GinDataPageAddItem(), ginDeletePage(), GinPageDeletePostingItem(), ginRedoInsert(), ginRedoSplit(), ginScanToDelete(), ginVacuumPostingTreeLeaves(), scanPostingTree(), and startScanEntry().
#define GinDataPageGetRightBound | ( | page | ) | ((ItemPointer) PageGetContents(page)) |
Definition at line 232 of file gin_private.h.
Referenced by dataIsMoveRight(), dataSplitPage(), ginDataFillRoot(), and ginRedoSplit().
#define GinGetDownlink | ( | itup | ) | GinItemPointerGetBlockNumber(&(itup)->t_tid) |
Definition at line 225 of file gin_private.h.
Referenced by entryFindChildPtr(), entryGetLeftMostPage(), entryLocateEntry(), entrySplitPage(), ginbulkdelete(), ginRedoInsert(), and ginVacuumEntryPage().
#define GinGetNPosting | ( | itup | ) | GinItemPointerGetOffsetNumber(&(itup)->t_tid) |
Definition at line 207 of file gin_private.h.
Referenced by addItemPointersToLeafTuple(), collectMatchBitmap(), GinShortenTuple(), ginVacuumEntryPage(), and startScanEntry().
#define GinGetNullCategory | ( | itup, | ||
ginstate | ||||
) | (*((GinNullCategory *) ((char*)(itup) + GinCategoryOffset(itup,ginstate)))) |
Definition at line 199 of file gin_private.h.
Referenced by gintuple_get_key().
#define GinGetPosting | ( | itup | ) | ((ItemPointer) ((char*)(itup) + GinGetPostingOffset(itup))) |
Definition at line 216 of file gin_private.h.
Referenced by addItemPointersToLeafTuple(), collectMatchBitmap(), GinFormTuple(), ginVacuumEntryPage(), and startScanEntry().
#define GinGetPostingOffset | ( | itup | ) | GinItemPointerGetBlockNumber(&(itup)->t_tid) |
Definition at line 214 of file gin_private.h.
Referenced by GinFormInteriorTuple(), and GinShortenTuple().
#define GinGetPostingTree | ( | itup | ) | GinItemPointerGetBlockNumber(&(itup)->t_tid) |
Definition at line 212 of file gin_private.h.
Referenced by collectMatchBitmap(), ginEntryInsert(), and startScanEntry().
#define GinGetUseFastUpdate | ( | relation | ) |
((relation)->rd_options ? \ ((GinOptions *) (relation)->rd_options)->useFastUpdate : GIN_DEFAULT_USE_FASTUPDATE)
Definition at line 268 of file gin_private.h.
Referenced by gininsert().
#define GinIsPostingTree | ( | itup | ) | (GinGetNPosting(itup) == GIN_TREE_POSTING) |
Definition at line 210 of file gin_private.h.
Referenced by addItemPointersToLeafTuple(), collectMatchBitmap(), ginEntryInsert(), GinFormInteriorTuple(), ginVacuumEntryPage(), and startScanEntry().
#define GinItemPointerGetBlockNumber | ( | pointer | ) | BlockIdGetBlockNumber(&(pointer)->ip_blkid) |
Definition at line 129 of file gin_private.h.
Referenced by ginCompareItemPointers(), keyGetItem(), and scanGetItem().
#define GinItemPointerGetOffsetNumber | ( | pointer | ) | ((pointer)->ip_posid) |
Definition at line 132 of file gin_private.h.
Referenced by ginCompareItemPointers().
#define GinListPageSize ( BLCKSZ - SizeOfPageHeaderData - MAXALIGN(sizeof(GinPageOpaqueData)) ) |
Definition at line 255 of file gin_private.h.
Referenced by ginHeapTupleFastInsert(), and makeSublist().
#define GinMaxItemSize |
MAXALIGN_DOWN(((BLCKSZ - SizeOfPageHeaderData - \ MAXALIGN(sizeof(GinPageOpaqueData))) / 3 - sizeof(ItemIdData)))
Definition at line 218 of file gin_private.h.
Referenced by GinFormTuple().
#define GinMaxLeafDataItems |
((BLCKSZ - MAXALIGN(SizeOfPageHeaderData) - \ MAXALIGN(sizeof(ItemPointerData)) - \ MAXALIGN(sizeof(GinPageOpaqueData))) \ / sizeof(ItemPointerData))
Definition at line 246 of file gin_private.h.
Referenced by buildFreshLeafTuple(), and createPostingTree().
#define GinPageGetMeta | ( | p | ) | ((GinMetaPageData *) PageGetContents(p)) |
Definition at line 101 of file gin_private.h.
Referenced by ginGetStats(), ginHeapTupleFastInsert(), GinInitMetabuffer(), ginInsertCleanup(), ginRedoDeleteListPages(), ginRedoUpdateMetapage(), ginUpdateStats(), pgstatginindex(), scanPendingInsert(), and shiftList().
#define GinPageGetOpaque | ( | page | ) | ( (GinPageOpaque) PageGetSpecialPointer(page) ) |
Definition at line 107 of file gin_private.h.
Referenced by createPostingTree(), dataFindChildPtr(), dataGetLeftMostPage(), dataIsEnoughSpace(), dataLocateItem(), dataLocateLeafItem(), dataPlaceToPage(), dataSplitPage(), entryGetNextItem(), entrySplitPage(), findItemInPostingPage(), ginbulkdelete(), ginContinueSplit(), GinDataPageAddItem(), ginDeletePage(), ginFindLeafPage(), ginFindParents(), ginHeapTupleFastInsert(), GinInitPage(), ginInsertCleanup(), ginInsertValue(), GinPageDeletePostingItem(), ginRedoCreatePTree(), ginRedoDeleteListPages(), ginRedoDeletePage(), ginRedoInsertListPage(), ginRedoSplit(), ginRedoUpdateMetapage(), ginRedoVacuumPage(), ginScanToDelete(), ginVacuumPostingTreeLeaves(), moveRightIfItNeeded(), scanGetCandidate(), scanPostingTree(), shiftList(), startScanEntry(), writeListPage(), and xlogVacuumPage().
#define GinPageHasFullRow | ( | page | ) | ( GinPageGetOpaque(page)->flags & GIN_LIST_FULLROW ) |
Definition at line 116 of file gin_private.h.
Referenced by collectMatchesForHeapRow(), ginInsertCleanup(), and scanGetCandidate().
#define GinPageIsData | ( | page | ) | ( GinPageGetOpaque(page)->flags & GIN_DATA ) |
Definition at line 112 of file gin_private.h.
Referenced by dataFindChildPtr(), dataGetLeftMostPage(), dataIsEnoughSpace(), dataLocateItem(), dataLocateLeafItem(), dataPlaceToPage(), dataPrepareData(), entryFindChildPtr(), entryGetLeftMostPage(), entryIsEnoughSpace(), entryLocateEntry(), entryLocateLeafEntry(), entryPreparePage(), ginbulkdelete(), ginRedoDeletePage(), ginRedoInsert(), ginRedoVacuumPage(), ginScanToDelete(), ginvacuumcleanup(), ginVacuumPostingTreeLeaves(), and xlogVacuumPage().
#define GinPageIsDeleted | ( | page | ) | ( GinPageGetOpaque(page)->flags & GIN_DELETED) |
Definition at line 119 of file gin_private.h.
Referenced by ginInsertCleanup(), GinNewBuffer(), ginvacuumcleanup(), and shiftList().
#define GinPageIsLeaf | ( | page | ) | ( GinPageGetOpaque(page)->flags & GIN_LEAF ) |
Definition at line 109 of file gin_private.h.
Referenced by collectMatchBitmap(), dataFindChildPtr(), dataGetLeftMostPage(), dataIsEnoughSpace(), dataLocateItem(), dataLocateLeafItem(), dataPlaceToPage(), dataPrepareData(), dataSplitPage(), entryFindChildPtr(), entryGetLeftMostPage(), entryLocateEntry(), entryLocateLeafEntry(), entryPlaceToPage(), entryPreparePage(), entrySplitPage(), ginbulkdelete(), ginContinueSplit(), ginFindLeafPage(), ginFindParents(), GinFormInteriorTuple(), GinPageDeletePostingItem(), ginRedoDeletePage(), ginRedoInsert(), ginScanToDelete(), ginTraverseLock(), ginvacuumcleanup(), ginVacuumPostingTreeLeaves(), and xlogVacuumPage().
#define GinPageIsList | ( | page | ) | ( GinPageGetOpaque(page)->flags & GIN_LIST ) |
Definition at line 114 of file gin_private.h.
Referenced by ginvacuumcleanup().
#define GinPageRightMost | ( | page | ) | ( GinPageGetOpaque(page)->rightlink == InvalidBlockNumber) |
Definition at line 123 of file gin_private.h.
Referenced by dataIsEnoughSpace(), dataIsMoveRight(), dataPlaceToPage(), dataSplitPage(), entryIsMoveRight(), entryLocateEntry(), ginScanToDelete(), moveRightIfItNeeded(), and scanPostingTree().
#define GinPageSetData | ( | page | ) | ( GinPageGetOpaque(page)->flags |= GIN_DATA ) |
Definition at line 113 of file gin_private.h.
#define GinPageSetDeleted | ( | page | ) | ( GinPageGetOpaque(page)->flags |= GIN_DELETED) |
Definition at line 120 of file gin_private.h.
#define GinPageSetFullRow | ( | page | ) | ( GinPageGetOpaque(page)->flags |= GIN_LIST_FULLROW ) |
Definition at line 117 of file gin_private.h.
Referenced by ginRedoInsertListPage(), and writeListPage().
#define GinPageSetLeaf | ( | page | ) | ( GinPageGetOpaque(page)->flags |= GIN_LEAF ) |
Definition at line 110 of file gin_private.h.
#define GinPageSetList | ( | page | ) | ( GinPageGetOpaque(page)->flags |= GIN_LIST ) |
Definition at line 115 of file gin_private.h.
#define GinPageSetNonDeleted | ( | page | ) | ( GinPageGetOpaque(page)->flags &= ~GIN_DELETED) |
Definition at line 121 of file gin_private.h.
#define GinPageSetNonLeaf | ( | page | ) | ( GinPageGetOpaque(page)->flags &= ~GIN_LEAF ) |
Definition at line 111 of file gin_private.h.
#define GinSetDownlink | ( | itup, | ||
blkno | ||||
) | ItemPointerSet(&(itup)->t_tid, blkno, InvalidOffsetNumber) |
Definition at line 226 of file gin_private.h.
Referenced by entryPreparePage(), GinFormInteriorTuple(), and ginRedoInsert().
#define GinSetNPosting | ( | itup, | ||
n | ||||
) | ItemPointerSetOffsetNumber(&(itup)->t_tid,n) |
Definition at line 208 of file gin_private.h.
Referenced by GinFormTuple(), and GinShortenTuple().
#define GinSetNullCategory | ( | itup, | ||
ginstate, | ||||
c | ||||
) | (*((GinNullCategory *) ((char*)(itup) + GinCategoryOffset(itup,ginstate))) = (c)) |
Definition at line 201 of file gin_private.h.
Referenced by GinFormTuple().
#define GinSetPostingOffset | ( | itup, | ||
n | ||||
) | ItemPointerSetBlockNumber(&(itup)->t_tid,n) |
Definition at line 215 of file gin_private.h.
Referenced by GinFormTuple().
#define GinSetPostingTree | ( | itup, | ||
blkno | ||||
) | ( GinSetNPosting((itup),GIN_TREE_POSTING), ItemPointerSetBlockNumber(&(itup)->t_tid, blkno) ) |
Definition at line 211 of file gin_private.h.
Referenced by addItemPointersToLeafTuple(), and buildFreshLeafTuple().
#define GinSizeOfDataPageItem | ( | page | ) | (GinPageIsLeaf(page) ? sizeof(ItemPointerData) : sizeof(PostingItem)) |
Definition at line 235 of file gin_private.h.
Referenced by dataPlaceToPage(), dataSplitPage(), GinDataPageAddItem(), ginRedoSplit(), and ginRedoVacuumPage().
#define ItemPointerIsLossyPage | ( | p | ) |
(GinItemPointerGetOffsetNumber(p) == (OffsetNumber)0xffff && \ GinItemPointerGetBlockNumber(p) != InvalidBlockNumber)
Definition at line 157 of file gin_private.h.
Referenced by gingetbitmap(), and scanGetItem().
#define ItemPointerIsMax | ( | p | ) |
(GinItemPointerGetOffsetNumber(p) == (OffsetNumber)0xffff && \ GinItemPointerGetBlockNumber(p) == InvalidBlockNumber)
Definition at line 152 of file gin_private.h.
Referenced by keyGetItem(), and scanGetItem().
#define ItemPointerIsMin | ( | p | ) |
(GinItemPointerGetOffsetNumber(p) == (OffsetNumber)0 && \ GinItemPointerGetBlockNumber(p) == (BlockNumber)0)
Definition at line 147 of file gin_private.h.
#define ItemPointerSetLossyPage | ( | p, | ||
b | ||||
) | ItemPointerSet((p), (b), (OffsetNumber)0xffff) |
Definition at line 155 of file gin_private.h.
Referenced by entryGetItem(), and keyGetItem().
#define ItemPointerSetMax | ( | p | ) | ItemPointerSet((p), InvalidBlockNumber, (OffsetNumber)0xffff) |
Definition at line 150 of file gin_private.h.
Referenced by keyGetItem(), and scanGetItem().
#define ItemPointerSetMin | ( | p | ) | ItemPointerSet((p), (BlockNumber)0, (OffsetNumber)0) |
Definition at line 145 of file gin_private.h.
Referenced by ginFillScanEntry(), ginFillScanKey(), gingetbitmap(), startScanEntry(), and startScanKey().
#define PostingItemGetBlockNumber | ( | pointer | ) | BlockIdGetBlockNumber(&(pointer)->child_blkno) |
Definition at line 171 of file gin_private.h.
Referenced by dataFindChildPtr(), dataGetLeftMostPage(), dataLocateItem(), dataSplitPage(), ginDeletePage(), ginRedoInsert(), ginScanToDelete(), and ginVacuumPostingTreeLeaves().
#define PostingItemSetBlockNumber | ( | pointer, | ||
blockNumber | ||||
) | BlockIdSet(&((pointer)->child_blkno), (blockNumber)) |
Definition at line 174 of file gin_private.h.
Referenced by dataPrepareData(), dataSplitPage(), ginContinueSplit(), ginDataFillRoot(), and ginRedoInsert().
#define XLOG_GIN_CREATE_INDEX 0x00 |
Definition at line 317 of file gin_private.h.
Referenced by gin_desc(), gin_redo(), and ginbuild().
#define XLOG_GIN_CREATE_PTREE 0x10 |
Definition at line 319 of file gin_private.h.
Referenced by createPostingTree(), gin_desc(), and gin_redo().
#define XLOG_GIN_DELETE_LISTPAGE 0x80 |
Definition at line 418 of file gin_private.h.
Referenced by gin_desc(), gin_redo(), and shiftList().
#define XLOG_GIN_DELETE_PAGE 0x50 |
Definition at line 381 of file gin_private.h.
Referenced by gin_desc(), gin_redo(), and ginDeletePage().
#define XLOG_GIN_INSERT 0x20 |
Definition at line 329 of file gin_private.h.
Referenced by gin_desc(), gin_redo(), and ginInsertValue().
#define XLOG_GIN_INSERT_LISTPAGE 0x70 |
Definition at line 407 of file gin_private.h.
Referenced by gin_desc(), gin_redo(), and writeListPage().
#define XLOG_GIN_SPLIT 0x30 |
Definition at line 348 of file gin_private.h.
Referenced by gin_desc(), gin_redo(), and ginInsertValue().
#define XLOG_GIN_UPDATE_META_PAGE 0x60 |
Definition at line 393 of file gin_private.h.
Referenced by gin_desc(), gin_redo(), ginHeapTupleFastInsert(), and ginUpdateStats().
#define XLOG_GIN_VACUUM_PAGE 0x40 |
Definition at line 371 of file gin_private.h.
Referenced by gin_desc(), gin_redo(), and xlogVacuumPage().
typedef struct GinBtreeData* GinBtree |
Definition at line 472 of file gin_private.h.
typedef struct GinBtreeData GinBtreeData |
typedef struct GinBtreeStack GinBtreeStack |
typedef struct GinEntryAccumulator GinEntryAccumulator |
typedef struct GinMetaPageData GinMetaPageData |
typedef signed char GinNullCategory |
Definition at line 185 of file gin_private.h.
typedef struct GinOptions GinOptions |
typedef GinPageOpaqueData* GinPageOpaque |
Definition at line 43 of file gin_private.h.
typedef struct GinPageOpaqueData GinPageOpaqueData |
typedef struct GinScanEntryData* GinScanEntry |
Definition at line 575 of file gin_private.h.
typedef struct GinScanEntryData GinScanEntryData |
typedef struct GinScanKeyData* GinScanKey |
Definition at line 573 of file gin_private.h.
typedef struct GinScanKeyData GinScanKeyData |
typedef GinScanOpaqueData* GinScanOpaque |
Definition at line 660 of file gin_private.h.
typedef struct GinScanOpaqueData GinScanOpaqueData |
typedef struct GinTupleCollector GinTupleCollector |
typedef struct ginxlogCreatePostingTree ginxlogCreatePostingTree |
typedef struct ginxlogDeleteListPages ginxlogDeleteListPages |
typedef struct ginxlogDeletePage ginxlogDeletePage |
typedef struct ginxlogInsert ginxlogInsert |
typedef struct ginxlogInsertListPage ginxlogInsertListPage |
typedef struct ginxlogSplit ginxlogSplit |
typedef struct ginxlogUpdateMeta ginxlogUpdateMeta |
typedef struct ginxlogVacuumPage ginxlogVacuumPage |
void freeGinBtreeStack | ( | GinBtreeStack * | stack | ) |
Definition at line 152 of file ginbtree.c.
References GinBtreeStack::buffer, InvalidBuffer, GinBtreeStack::parent, pfree(), and ReleaseBuffer().
Referenced by ginEntryInsert(), ginInsertItemPointers(), ginInsertValue(), scanPostingTree(), and startScanEntry().
{ while (stack) { GinBtreeStack *tmp = stack->parent; if (stack->buffer != InvalidBuffer) ReleaseBuffer(stack->buffer); pfree(stack); stack = tmp; } }
void ginBeginBAScan | ( | BuildAccumulator * | accum | ) |
Definition at line 248 of file ginbulk.c.
References LeftRightWalk, rb_begin_iterate(), and BuildAccumulator::tree.
Referenced by ginbuild(), ginBuildCallback(), and ginInsertCleanup().
{ rb_begin_iterate(accum->tree, LeftRightWalk); }
Datum ginbeginscan | ( | PG_FUNCTION_ARGS | ) |
Definition at line 25 of file ginscan.c.
References ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE, ALLOCSET_DEFAULT_MINSIZE, AllocSetContextCreate(), Assert, CurrentMemoryContext, GinScanOpaqueData::ginstate, IndexScanDescData::indexRelation, initGinState(), GinScanOpaqueData::keys, GinScanOpaqueData::nkeys, IndexScanDescData::opaque, palloc(), PG_GETARG_INT32, PG_GETARG_POINTER, PG_RETURN_POINTER, RelationGetIndexScan(), and GinScanOpaqueData::tempCtx.
{ Relation rel = (Relation) PG_GETARG_POINTER(0); int nkeys = PG_GETARG_INT32(1); int norderbys = PG_GETARG_INT32(2); IndexScanDesc scan; GinScanOpaque so; /* no order by operators allowed */ Assert(norderbys == 0); scan = RelationGetIndexScan(rel, nkeys, norderbys); /* allocate private workspace */ so = (GinScanOpaque) palloc(sizeof(GinScanOpaqueData)); so->keys = NULL; so->nkeys = 0; so->tempCtx = AllocSetContextCreate(CurrentMemoryContext, "Gin scan temporary context", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); initGinState(&so->ginstate, scan->indexRelation); scan->opaque = so; PG_RETURN_POINTER(scan); }
Datum ginbuild | ( | PG_FUNCTION_ARGS | ) |
Definition at line 381 of file gininsert.c.
References GinBuildState::accum, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE, ALLOCSET_DEFAULT_MINSIZE, AllocSetContextCreate(), XLogRecData::buffer, BufferGetPage, GinBuildState::buildStats, CHECK_FOR_INTERRUPTS, CurrentMemoryContext, XLogRecData::data, elog, END_CRIT_SECTION, ERROR, GinBuildState::funcCtx, GIN_LEAF, ginBeginBAScan(), ginBuildCallback(), ginEntryInsert(), ginGetBAEntry(), ginInitBA(), GinInitBuffer(), GinInitMetabuffer(), GinNewBuffer(), BuildAccumulator::ginstate, GinBuildState::ginstate, ginUpdateStats(), IndexBuildResult::heap_tuples, IndexBuildResult::index_tuples, IndexBuildHeapScan(), GinBuildState::indtuples, initGinState(), XLogRecData::len, sort-test::list, MarkBufferDirty(), MemoryContextDelete(), MemoryContextSwitchTo(), GinStatsData::nEntryPages, XLogRecData::next, NULL, PageSetLSN, palloc(), PG_GETARG_POINTER, PG_RETURN_POINTER, RelationData::rd_node, RelationGetNumberOfBlocks, RelationGetRelationName, RelationNeedsWAL, START_CRIT_SECTION, GinBuildState::tmpCtx, UnlockReleaseBuffer(), XLOG_GIN_CREATE_INDEX, and XLogInsert().
{ Relation heap = (Relation) PG_GETARG_POINTER(0); Relation index = (Relation) PG_GETARG_POINTER(1); IndexInfo *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2); IndexBuildResult *result; double reltuples; GinBuildState buildstate; Buffer RootBuffer, MetaBuffer; ItemPointerData *list; Datum key; GinNullCategory category; uint32 nlist; MemoryContext oldCtx; OffsetNumber attnum; if (RelationGetNumberOfBlocks(index) != 0) elog(ERROR, "index \"%s\" already contains data", RelationGetRelationName(index)); initGinState(&buildstate.ginstate, index); buildstate.indtuples = 0; memset(&buildstate.buildStats, 0, sizeof(GinStatsData)); /* initialize the meta page */ MetaBuffer = GinNewBuffer(index); /* initialize the root page */ RootBuffer = GinNewBuffer(index); START_CRIT_SECTION(); GinInitMetabuffer(MetaBuffer); MarkBufferDirty(MetaBuffer); GinInitBuffer(RootBuffer, GIN_LEAF); MarkBufferDirty(RootBuffer); if (RelationNeedsWAL(index)) { XLogRecPtr recptr; XLogRecData rdata; Page page; rdata.buffer = InvalidBuffer; rdata.data = (char *) &(index->rd_node); rdata.len = sizeof(RelFileNode); rdata.next = NULL; recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_CREATE_INDEX, &rdata); page = BufferGetPage(RootBuffer); PageSetLSN(page, recptr); page = BufferGetPage(MetaBuffer); PageSetLSN(page, recptr); } UnlockReleaseBuffer(MetaBuffer); UnlockReleaseBuffer(RootBuffer); END_CRIT_SECTION(); /* count the root as first entry page */ buildstate.buildStats.nEntryPages++; /* * create a temporary memory context that is reset once for each tuple * inserted into the index */ buildstate.tmpCtx = AllocSetContextCreate(CurrentMemoryContext, "Gin build temporary context", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); buildstate.funcCtx = AllocSetContextCreate(buildstate.tmpCtx, "Gin build temporary context for user-defined function", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); buildstate.accum.ginstate = &buildstate.ginstate; ginInitBA(&buildstate.accum); /* * Do the heap scan. We disallow sync scan here because dataPlaceToPage * prefers to receive tuples in TID order. */ reltuples = IndexBuildHeapScan(heap, index, indexInfo, false, ginBuildCallback, (void *) &buildstate); /* dump remaining entries to the index */ oldCtx = MemoryContextSwitchTo(buildstate.tmpCtx); ginBeginBAScan(&buildstate.accum); while ((list = ginGetBAEntry(&buildstate.accum, &attnum, &key, &category, &nlist)) != NULL) { /* there could be many entries, so be willing to abort here */ CHECK_FOR_INTERRUPTS(); ginEntryInsert(&buildstate.ginstate, attnum, key, category, list, nlist, &buildstate.buildStats); } MemoryContextSwitchTo(oldCtx); MemoryContextDelete(buildstate.tmpCtx); /* * Update metapage stats */ buildstate.buildStats.nTotalPages = RelationGetNumberOfBlocks(index); ginUpdateStats(index, &buildstate.buildStats); /* * Return statistics */ result = (IndexBuildResult *) palloc(sizeof(IndexBuildResult)); result->heap_tuples = reltuples; result->index_tuples = buildstate.indtuples; PG_RETURN_POINTER(result); }
Datum ginbuildempty | ( | PG_FUNCTION_ARGS | ) |
Definition at line 507 of file gininsert.c.
References BUFFER_LOCK_EXCLUSIVE, END_CRIT_SECTION, GIN_LEAF, GinInitBuffer(), GinInitMetabuffer(), INIT_FORKNUM, LockBuffer(), log_newpage_buffer(), MarkBufferDirty(), NULL, P_NEW, PG_GETARG_POINTER, PG_RETURN_VOID, RBM_NORMAL, ReadBufferExtended(), START_CRIT_SECTION, and UnlockReleaseBuffer().
{ Relation index = (Relation) PG_GETARG_POINTER(0); Buffer RootBuffer, MetaBuffer; /* An empty GIN index has two pages. */ MetaBuffer = ReadBufferExtended(index, INIT_FORKNUM, P_NEW, RBM_NORMAL, NULL); LockBuffer(MetaBuffer, BUFFER_LOCK_EXCLUSIVE); RootBuffer = ReadBufferExtended(index, INIT_FORKNUM, P_NEW, RBM_NORMAL, NULL); LockBuffer(RootBuffer, BUFFER_LOCK_EXCLUSIVE); /* Initialize and xlog metabuffer and root buffer. */ START_CRIT_SECTION(); GinInitMetabuffer(MetaBuffer); MarkBufferDirty(MetaBuffer); log_newpage_buffer(MetaBuffer); GinInitBuffer(RootBuffer, GIN_LEAF); MarkBufferDirty(RootBuffer); log_newpage_buffer(RootBuffer); END_CRIT_SECTION(); /* Unlock and release the buffers. */ UnlockReleaseBuffer(MetaBuffer); UnlockReleaseBuffer(RootBuffer); PG_RETURN_VOID(); }
Datum ginbulkdelete | ( | PG_FUNCTION_ARGS | ) |
Definition at line 577 of file ginvacuum.c.
References Assert, DataPageDeleteStack::blkno, BufferGetPage, GinVacuumState::callback, callback(), GinVacuumState::callback_state, 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(), NULL, IndexBulkDeleteResult::num_index_tuples, PageGetItem, PageGetItemId, PageGetMaxOffsetNumber, PageRestoreTempPage(), palloc0(), PG_GETARG_POINTER, PG_RETURN_POINTER, RBM_NORMAL, ReadBufferExtended(), GinVacuumState::result, START_CRIT_SECTION, IndexVacuumInfo::strategy, GinVacuumState::strategy, UnlockReleaseBuffer(), vacuum_delay_point(), and xlogVacuumPage().
{ IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0); IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1); IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(2); void *callback_state = (void *) PG_GETARG_POINTER(3); Relation index = info->index; BlockNumber blkno = GIN_ROOT_BLKNO; GinVacuumState gvs; Buffer buffer; BlockNumber rootOfPostingTree[BLCKSZ / (sizeof(IndexTupleData) + sizeof(ItemId))]; uint32 nRoot; gvs.index = index; gvs.callback = callback; gvs.callback_state = callback_state; gvs.strategy = info->strategy; initGinState(&gvs.ginstate, index); /* first time through? */ if (stats == NULL) { /* Yes, so initialize stats to zeroes */ stats = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult)); /* and cleanup any pending inserts */ ginInsertCleanup(&gvs.ginstate, true, stats); } /* we'll re-count the tuples each time */ stats->num_index_tuples = 0; gvs.result = stats; buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno, RBM_NORMAL, info->strategy); /* find leaf page */ for (;;) { Page page = BufferGetPage(buffer); IndexTuple itup; LockBuffer(buffer, GIN_SHARE); Assert(!GinPageIsData(page)); if (GinPageIsLeaf(page)) { LockBuffer(buffer, GIN_UNLOCK); LockBuffer(buffer, GIN_EXCLUSIVE); if (blkno == GIN_ROOT_BLKNO && !GinPageIsLeaf(page)) { LockBuffer(buffer, GIN_UNLOCK); continue; /* check it one more */ } break; } Assert(PageGetMaxOffsetNumber(page) >= FirstOffsetNumber); itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, FirstOffsetNumber)); blkno = GinGetDownlink(itup); Assert(blkno != InvalidBlockNumber); UnlockReleaseBuffer(buffer); buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno, RBM_NORMAL, info->strategy); } /* right now we found leftmost page in entry's BTree */ for (;;) { Page page = BufferGetPage(buffer); Page resPage; uint32 i; Assert(!GinPageIsData(page)); resPage = ginVacuumEntryPage(&gvs, buffer, rootOfPostingTree, &nRoot); blkno = GinPageGetOpaque(page)->rightlink; if (resPage) { START_CRIT_SECTION(); PageRestoreTempPage(resPage, page); MarkBufferDirty(buffer); xlogVacuumPage(gvs.index, buffer); UnlockReleaseBuffer(buffer); END_CRIT_SECTION(); } else { UnlockReleaseBuffer(buffer); } vacuum_delay_point(); for (i = 0; i < nRoot; i++) { ginVacuumPostingTree(&gvs, rootOfPostingTree[i]); vacuum_delay_point(); } if (blkno == InvalidBlockNumber) /* rightmost page */ break; buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno, RBM_NORMAL, info->strategy); LockBuffer(buffer, GIN_EXCLUSIVE); } PG_RETURN_POINTER(gvs.result); }
int ginCompareAttEntries | ( | GinState * | ginstate, | |
OffsetNumber | attnuma, | |||
Datum | a, | |||
GinNullCategory | categorya, | |||
OffsetNumber | attnumb, | |||
Datum | b, | |||
GinNullCategory | categoryb | |||
) |
Definition at line 302 of file ginutil.c.
References ginCompareEntries().
Referenced by cmpEntryAccumulator(), entryIsMoveRight(), entryLocateEntry(), and entryLocateLeafEntry().
{ /* attribute number is the first sort key */ if (attnuma != attnumb) return (attnuma < attnumb) ? -1 : 1; return ginCompareEntries(ginstate, attnuma, a, categorya, b, categoryb); }
int ginCompareEntries | ( | GinState * | ginstate, | |
OffsetNumber | attnum, | |||
Datum | a, | |||
GinNullCategory | categorya, | |||
Datum | b, | |||
GinNullCategory | categoryb | |||
) |
Definition at line 280 of file ginutil.c.
References GinState::compareFn, DatumGetInt32, FunctionCall2Coll(), GIN_CAT_NORM_KEY, and GinState::supportCollation.
Referenced by collectMatchBitmap(), collectMatchesForHeapRow(), ginCompareAttEntries(), and ginFillScanEntry().
{ /* if not of same null category, sort by that first */ if (categorya != categoryb) return (categorya < categoryb) ? -1 : 1; /* all null items in same category are equal */ if (categorya != GIN_CAT_NORM_KEY) return 0; /* both not null, so safe to call the compareFn */ return DatumGetInt32(FunctionCall2Coll(&ginstate->compareFn[attnum - 1], ginstate->supportCollation[attnum - 1], a, b)); }
int ginCompareItemPointers | ( | ItemPointer | a, | |
ItemPointer | b | |||
) |
Definition at line 21 of file gindatapage.c.
References GinItemPointerGetBlockNumber, and GinItemPointerGetOffsetNumber.
Referenced by dataIsMoveRight(), dataLocateItem(), dataLocateLeafItem(), entryGetNextItem(), findItemInPostingPage(), ginCombineData(), ginMergeItemPointers(), keyGetItem(), qsortCompareItemPointers(), and scanGetItem().
{ BlockNumber ba = GinItemPointerGetBlockNumber(a); BlockNumber bb = GinItemPointerGetBlockNumber(b); if (ba == bb) { OffsetNumber oa = GinItemPointerGetOffsetNumber(a); OffsetNumber ob = GinItemPointerGetOffsetNumber(b); if (oa == ob) return 0; return (oa > ob) ? 1 : -1; } return (ba > bb) ? 1 : -1; }
Definition at line 588 of file gindatapage.c.
References BufferGetBlockNumber(), BufferGetPage, GinDataPageAddItem(), GinDataPageGetRightBound, InvalidOffsetNumber, PostingItem::key, and PostingItemSetBlockNumber.
Referenced by ginRedoSplit().
{ Page page = BufferGetPage(root), lpage = BufferGetPage(lbuf), rpage = BufferGetPage(rbuf); PostingItem li, ri; li.key = *GinDataPageGetRightBound(lpage); PostingItemSetBlockNumber(&li, BufferGetBlockNumber(lbuf)); GinDataPageAddItem(page, &li, InvalidOffsetNumber); ri.key = *GinDataPageGetRightBound(rpage); PostingItemSetBlockNumber(&ri, BufferGetBlockNumber(rbuf)); GinDataPageAddItem(page, &ri, InvalidOffsetNumber); }
void GinDataPageAddItem | ( | Page | page, | |
void * | data, | |||
OffsetNumber | offset | |||
) |
Definition at line 282 of file gindatapage.c.
References GinDataPageGetItem, GinPageGetOpaque, GinSizeOfDataPageItem, InvalidOffsetNumber, and memmove.
Referenced by dataPlaceToPage(), ginDataFillRoot(), ginRedoInsert(), and ginRedoSplit().
{ OffsetNumber maxoff = GinPageGetOpaque(page)->maxoff; char *ptr; if (offset == InvalidOffsetNumber) { ptr = GinDataPageGetItem(page, maxoff + 1); } else { ptr = GinDataPageGetItem(page, offset); if (maxoff + 1 - offset != 0) memmove(ptr + GinSizeOfDataPageItem(page), ptr, (maxoff - offset + 1) * GinSizeOfDataPageItem(page)); } memcpy(ptr, data, GinSizeOfDataPageItem(page)); GinPageGetOpaque(page)->maxoff++; }
Datum ginendscan | ( | PG_FUNCTION_ARGS | ) |
Definition at line 430 of file ginscan.c.
References freeScanKeys(), MemoryContextDelete(), IndexScanDescData::opaque, pfree(), PG_GETARG_POINTER, PG_RETURN_VOID, and GinScanOpaqueData::tempCtx.
{ IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); GinScanOpaque so = (GinScanOpaque) scan->opaque; freeScanKeys(so); MemoryContextDelete(so->tempCtx); pfree(so); PG_RETURN_VOID(); }
Definition at line 682 of file ginentrypage.c.
References BufferGetPage, elog, ERROR, ginPageGetLinkItup(), IndexTupleSize, InvalidOffsetNumber, PageAddItem(), and pfree().
Referenced by ginRedoSplit().
{ Page page; IndexTuple itup; page = BufferGetPage(root); itup = ginPageGetLinkItup(lbuf); if (PageAddItem(page, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, false, false) == InvalidOffsetNumber) elog(ERROR, "failed to add item to index root page"); pfree(itup); itup = ginPageGetLinkItup(rbuf); if (PageAddItem(page, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, false, false) == InvalidOffsetNumber) elog(ERROR, "failed to add item to index root page"); pfree(itup); }
void ginEntryInsert | ( | GinState * | ginstate, | |
OffsetNumber | attnum, | |||
Datum | key, | |||
GinNullCategory | category, | |||
ItemPointerData * | items, | |||
uint32 | nitem, | |||
GinStatsData * | buildStats | |||
) |
Definition at line 247 of file gininsert.c.
References addItemPointersToLeafTuple(), GinPostingTreeScan::btree, GinBtreeStack::buffer, BufferGetPage, buildFreshLeafTuple(), GinBtreeData::entry, FALSE, GinBtreeData::findItem, freeGinBtreeStack(), GIN_UNLOCK, ginFindLeafPage(), GinGetPostingTree, ginInsertItemPointers(), ginInsertValue(), GinIsPostingTree, ginPrepareEntryScan(), ginPrepareScanPostingTree(), GinState::index, GinBtreeData::isBuild, GinBtreeData::isDelete, LockBuffer(), GinStatsData::nEntries, NULL, GinBtreeStack::off, PageGetItem, PageGetItemId, and pfree().
Referenced by ginbuild(), ginBuildCallback(), ginHeapTupleInsert(), and ginInsertCleanup().
{ GinBtreeData btree; GinBtreeStack *stack; IndexTuple itup; Page page; /* During index build, count the to-be-inserted entry */ if (buildStats) buildStats->nEntries++; ginPrepareEntryScan(&btree, attnum, key, category, ginstate); stack = ginFindLeafPage(&btree, NULL); page = BufferGetPage(stack->buffer); if (btree.findItem(&btree, stack)) { /* found pre-existing entry */ itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, stack->off)); if (GinIsPostingTree(itup)) { /* add entries to existing posting tree */ BlockNumber rootPostingTree = GinGetPostingTree(itup); GinPostingTreeScan *gdi; /* release all stack */ LockBuffer(stack->buffer, GIN_UNLOCK); freeGinBtreeStack(stack); /* insert into posting tree */ gdi = ginPrepareScanPostingTree(ginstate->index, rootPostingTree, FALSE); gdi->btree.isBuild = (buildStats != NULL); ginInsertItemPointers(gdi, items, nitem, buildStats); pfree(gdi); return; } /* modify an existing leaf entry */ itup = addItemPointersToLeafTuple(ginstate, itup, items, nitem, buildStats); btree.isDelete = TRUE; } else { /* no match, so construct a new leaf entry */ itup = buildFreshLeafTuple(ginstate, attnum, key, category, items, nitem, buildStats); } /* Insert the new or modified leaf tuple */ btree.entry = itup; ginInsertValue(&btree, stack, buildStats); pfree(itup); }
Datum* ginExtractEntries | ( | GinState * | ginstate, | |
OffsetNumber | attnum, | |||
Datum | value, | |||
bool | isNull, | |||
int32 * | nentries, | |||
GinNullCategory ** | categories | |||
) |
Definition at line 375 of file ginutil.c.
References arg, cmpEntriesArg::cmpDatumFunc, cmpEntries(), cmpEntriesArg::collation, GinState::compareFn, keyEntryData::datum, DatumGetPointer, GinState::extractValueFn, FunctionCall3Coll(), cmpEntriesArg::haveDups, i, keyEntryData::isnull, NULL, palloc(), palloc0(), pfree(), PointerGetDatum, qsort_arg(), and GinState::supportCollation.
Referenced by ginHeapTupleBulkInsert(), ginHeapTupleFastCollect(), and ginHeapTupleInsert().
{ Datum *entries; bool *nullFlags; int32 i; /* * We don't call the extractValueFn on a null item. Instead generate a * placeholder. */ if (isNull) { *nentries = 1; entries = (Datum *) palloc(sizeof(Datum)); entries[0] = (Datum) 0; *categories = (GinNullCategory *) palloc(sizeof(GinNullCategory)); (*categories)[0] = GIN_CAT_NULL_ITEM; return entries; } /* OK, call the opclass's extractValueFn */ nullFlags = NULL; /* in case extractValue doesn't set it */ entries = (Datum *) DatumGetPointer(FunctionCall3Coll(&ginstate->extractValueFn[attnum - 1], ginstate->supportCollation[attnum - 1], value, PointerGetDatum(nentries), PointerGetDatum(&nullFlags))); /* * Generate a placeholder if the item contained no keys. */ if (entries == NULL || *nentries <= 0) { *nentries = 1; entries = (Datum *) palloc(sizeof(Datum)); entries[0] = (Datum) 0; *categories = (GinNullCategory *) palloc(sizeof(GinNullCategory)); (*categories)[0] = GIN_CAT_EMPTY_ITEM; return entries; } /* * If the extractValueFn didn't create a nullFlags array, create one, * assuming that everything's non-null. Otherwise, run through the array * and make sure each value is exactly 0 or 1; this ensures binary * compatibility with the GinNullCategory representation. */ if (nullFlags == NULL) nullFlags = (bool *) palloc0(*nentries * sizeof(bool)); else { for (i = 0; i < *nentries; i++) nullFlags[i] = (nullFlags[i] ? true : false); } /* now we can use the nullFlags as category codes */ *categories = (GinNullCategory *) nullFlags; /* * If there's more than one key, sort and unique-ify. * * XXX Using qsort here is notationally painful, and the overhead is * pretty bad too. For small numbers of keys it'd likely be better to use * a simple insertion sort. */ if (*nentries > 1) { keyEntryData *keydata; cmpEntriesArg arg; keydata = (keyEntryData *) palloc(*nentries * sizeof(keyEntryData)); for (i = 0; i < *nentries; i++) { keydata[i].datum = entries[i]; keydata[i].isnull = nullFlags[i]; } arg.cmpDatumFunc = &ginstate->compareFn[attnum - 1]; arg.collation = ginstate->supportCollation[attnum - 1]; arg.haveDups = false; qsort_arg(keydata, *nentries, sizeof(keyEntryData), cmpEntries, (void *) &arg); if (arg.haveDups) { /* there are duplicates, must get rid of 'em */ int32 j; entries[0] = keydata[0].datum; nullFlags[0] = keydata[0].isnull; j = 1; for (i = 1; i < *nentries; i++) { if (cmpEntries(&keydata[i - 1], &keydata[i], &arg) != 0) { entries[j] = keydata[i].datum; nullFlags[j] = keydata[i].isnull; j++; } } *nentries = j; } else { /* easy, no duplicates */ for (i = 0; i < *nentries; i++) { entries[i] = keydata[i].datum; nullFlags[i] = keydata[i].isnull; } } pfree(keydata); } return entries; }
GinBtreeStack* ginFindLeafPage | ( | GinBtree | btree, | |
GinBtreeStack * | stack | |||
) |
Definition at line 74 of file ginbtree.c.
References Assert, GinBtreeStack::blkno, GinBtreeStack::buffer, BufferGetPage, FALSE, GinBtreeData::findChildPage, GinBtreeData::fullScan, GIN_ROOT_BLKNO, GIN_UNLOCK, GinPageGetOpaque, GinPageIsLeaf, ginPrepareFindLeafPage(), ginTraverseLock(), GinBtreeData::index, InvalidBlockNumber, GinBtreeData::isMoveRight, LockBuffer(), GinBtreeStack::off, palloc(), GinBtreeStack::parent, GinBtreeStack::predictNumber, ReadBuffer(), ReleaseAndReadBuffer(), and GinBtreeData::searchMode.
Referenced by ginEntryInsert(), ginInsertItemPointers(), ginScanBeginPostingTree(), and startScanEntry().
{ bool isfirst = TRUE; BlockNumber rootBlkno; if (!stack) stack = ginPrepareFindLeafPage(btree, GIN_ROOT_BLKNO); rootBlkno = stack->blkno; for (;;) { Page page; BlockNumber child; int access = GIN_SHARE; stack->off = InvalidOffsetNumber; page = BufferGetPage(stack->buffer); if (isfirst) { if (GinPageIsLeaf(page) && !btree->searchMode) access = GIN_EXCLUSIVE; isfirst = FALSE; } else access = ginTraverseLock(stack->buffer, btree->searchMode); /* * ok, page is correctly locked, we should check to move right .., * root never has a right link, so small optimization */ while (btree->fullScan == FALSE && stack->blkno != rootBlkno && btree->isMoveRight(btree, page)) { BlockNumber rightlink = GinPageGetOpaque(page)->rightlink; if (rightlink == InvalidBlockNumber) /* rightmost page */ break; stack->blkno = rightlink; LockBuffer(stack->buffer, GIN_UNLOCK); stack->buffer = ReleaseAndReadBuffer(stack->buffer, btree->index, stack->blkno); LockBuffer(stack->buffer, access); page = BufferGetPage(stack->buffer); } if (GinPageIsLeaf(page)) /* we found, return locked page */ return stack; /* now we have correct buffer, try to find child */ child = btree->findChildPage(btree, stack); LockBuffer(stack->buffer, GIN_UNLOCK); Assert(child != InvalidBlockNumber); Assert(stack->blkno != child); if (btree->searchMode) { /* in search mode we may forget path to leaf */ stack->blkno = child; stack->buffer = ReleaseAndReadBuffer(stack->buffer, btree->index, stack->blkno); } else { GinBtreeStack *ptr = (GinBtreeStack *) palloc(sizeof(GinBtreeStack)); ptr->parent = stack; stack = ptr; stack->blkno = child; stack->buffer = ReadBuffer(btree->index, stack->blkno); stack->predictNumber = 1; } } }
void ginFindParents | ( | GinBtree | btree, | |
GinBtreeStack * | stack, | |||
BlockNumber | rootBlkno | |||
) |
Definition at line 173 of file ginbtree.c.
References Assert, GinBtreeStack::blkno, GinBtreeStack::buffer, BufferGetBlockNumber(), BufferGetPage, elog, ERROR, GinBtreeData::findChildPtr, GinBtreeData::getLeftMostPage, GIN_EXCLUSIVE, GIN_UNLOCK, GinPageGetOpaque, GinPageIsLeaf, GinBtreeData::index, InvalidBlockNumber, InvalidOffsetNumber, LockBuffer(), GinBtreeStack::off, palloc(), GinBtreeStack::parent, ReadBuffer(), and ReleaseBuffer().
Referenced by ginContinueSplit(), and ginInsertValue().
{ Page page; Buffer buffer; BlockNumber blkno, leftmostBlkno; OffsetNumber offset; GinBtreeStack *root = stack->parent; GinBtreeStack *ptr; if (!root) { /* XLog mode... */ root = (GinBtreeStack *) palloc(sizeof(GinBtreeStack)); root->blkno = rootBlkno; root->buffer = ReadBuffer(btree->index, rootBlkno); LockBuffer(root->buffer, GIN_EXCLUSIVE); root->parent = NULL; } else { /* * find root, we should not release root page until update is * finished!! */ while (root->parent) { ReleaseBuffer(root->buffer); root = root->parent; } Assert(root->blkno == rootBlkno); Assert(BufferGetBlockNumber(root->buffer) == rootBlkno); LockBuffer(root->buffer, GIN_EXCLUSIVE); } root->off = InvalidOffsetNumber; page = BufferGetPage(root->buffer); Assert(!GinPageIsLeaf(page)); /* check trivial case */ if ((root->off = btree->findChildPtr(btree, page, stack->blkno, InvalidOffsetNumber)) != InvalidOffsetNumber) { stack->parent = root; return; } leftmostBlkno = blkno = btree->getLeftMostPage(btree, page); LockBuffer(root->buffer, GIN_UNLOCK); Assert(blkno != InvalidBlockNumber); for (;;) { buffer = ReadBuffer(btree->index, blkno); LockBuffer(buffer, GIN_EXCLUSIVE); page = BufferGetPage(buffer); if (GinPageIsLeaf(page)) elog(ERROR, "Lost path"); leftmostBlkno = btree->getLeftMostPage(btree, page); while ((offset = btree->findChildPtr(btree, page, stack->blkno, InvalidOffsetNumber)) == InvalidOffsetNumber) { blkno = GinPageGetOpaque(page)->rightlink; LockBuffer(buffer, GIN_UNLOCK); ReleaseBuffer(buffer); if (blkno == InvalidBlockNumber) break; buffer = ReadBuffer(btree->index, blkno); LockBuffer(buffer, GIN_EXCLUSIVE); page = BufferGetPage(buffer); } if (blkno != InvalidBlockNumber) { ptr = (GinBtreeStack *) palloc(sizeof(GinBtreeStack)); ptr->blkno = blkno; ptr->buffer = buffer; ptr->parent = root; /* it's may be wrong, but in next call we will * correct */ ptr->off = offset; stack->parent = ptr; return; } blkno = leftmostBlkno; } }
IndexTuple GinFormTuple | ( | GinState * | ginstate, | |
OffsetNumber | attnum, | |||
Datum | key, | |||
GinNullCategory | category, | |||
ItemPointerData * | ipd, | |||
uint32 | nipd, | |||
bool | errorTooBig | |||
) |
Definition at line 36 of file ginentrypage.c.
References Assert, ereport, errcode(), errmsg(), ERROR, GIN_CAT_NORM_KEY, GinCategoryOffset, GinGetPosting, GinMaxItemSize, GinSetNPosting, GinSetNullCategory, GinSetPostingOffset, GinState::index, index_form_tuple(), INDEX_SIZE_MASK, IndexTupleHasNulls, IndexTupleSize, Max, MAXALIGN, Min, GinState::oneCol, pfree(), RelationGetRelationName, repalloc(), SHORTALIGN, IndexTupleData::t_info, GinState::tupdesc, and UInt16GetDatum.
Referenced by addItemPointersToLeafTuple(), buildFreshLeafTuple(), ginHeapTupleFastCollect(), and ginVacuumEntryPage().
{ Datum datums[2]; bool isnull[2]; IndexTuple itup; uint32 newsize; /* Build the basic tuple: optional column number, plus key datum */ if (ginstate->oneCol) { datums[0] = key; isnull[0] = (category != GIN_CAT_NORM_KEY); } else { datums[0] = UInt16GetDatum(attnum); isnull[0] = false; datums[1] = key; isnull[1] = (category != GIN_CAT_NORM_KEY); } itup = index_form_tuple(ginstate->tupdesc[attnum - 1], datums, isnull); /* * Determine and store offset to the posting list, making sure there is * room for the category byte if needed. * * Note: because index_form_tuple MAXALIGNs the tuple size, there may well * be some wasted pad space. Is it worth recomputing the data length to * prevent that? That would also allow us to Assert that the real data * doesn't overlap the GinNullCategory byte, which this code currently * takes on faith. */ newsize = IndexTupleSize(itup); if (IndexTupleHasNulls(itup)) { uint32 minsize; Assert(category != GIN_CAT_NORM_KEY); minsize = GinCategoryOffset(itup, ginstate) + sizeof(GinNullCategory); newsize = Max(newsize, minsize); } newsize = SHORTALIGN(newsize); GinSetPostingOffset(itup, newsize); GinSetNPosting(itup, nipd); /* * Add space needed for posting list, if any. Then check that the tuple * won't be too big to store. */ newsize += sizeof(ItemPointerData) * nipd; newsize = MAXALIGN(newsize); if (newsize > Min(INDEX_SIZE_MASK, GinMaxItemSize)) { if (errorTooBig) ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("index row size %lu exceeds maximum %lu for index \"%s\"", (unsigned long) newsize, (unsigned long) Min(INDEX_SIZE_MASK, GinMaxItemSize), RelationGetRelationName(ginstate->index)))); pfree(itup); return NULL; } /* * Resize tuple if needed */ if (newsize != IndexTupleSize(itup)) { itup = repalloc(itup, newsize); /* set new size in tuple header */ itup->t_info &= ~INDEX_SIZE_MASK; itup->t_info |= newsize; } /* * Insert category byte, if needed */ if (category != GIN_CAT_NORM_KEY) { Assert(IndexTupleHasNulls(itup)); GinSetNullCategory(itup, ginstate, category); } /* * Copy in the posting list, if provided */ if (ipd) memcpy(GinGetPosting(itup), ipd, sizeof(ItemPointerData) * nipd); return itup; }
ItemPointerData* ginGetBAEntry | ( | BuildAccumulator * | accum, | |
OffsetNumber * | attnum, | |||
Datum * | key, | |||
GinNullCategory * | category, | |||
uint32 * | n | |||
) |
Definition at line 259 of file ginbulk.c.
References Assert, GinEntryAccumulator::attnum, GinEntryAccumulator::category, GinEntryAccumulator::count, GinEntryAccumulator::key, GinEntryAccumulator::list, sort-test::list, NULL, qsort, qsortCompareItemPointers(), rb_iterate(), GinEntryAccumulator::shouldSort, and BuildAccumulator::tree.
Referenced by ginbuild(), ginBuildCallback(), and ginInsertCleanup().
{ GinEntryAccumulator *entry; ItemPointerData *list; entry = (GinEntryAccumulator *) rb_iterate(accum->tree); if (entry == NULL) return NULL; /* no more entries */ *attnum = entry->attnum; *key = entry->key; *category = entry->category; list = entry->list; *n = entry->count; Assert(list != NULL && entry->count > 0); if (entry->shouldSort && entry->count > 1) qsort(list, entry->count, sizeof(ItemPointerData), qsortCompareItemPointers); return list; }
Datum gingetbitmap | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1505 of file ginget.c.
References CHECK_FOR_INTERRUPTS, GinIsNewKey, GinIsVoidRes, ginNewScanKey(), ItemPointerGetBlockNumber, ItemPointerIsLossyPage, ItemPointerSetMin, PG_GETARG_POINTER, PG_RETURN_INT64, scanGetItem(), scanPendingInsert(), startScan(), tbm_add_page(), and tbm_add_tuples().
{ IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); TIDBitmap *tbm = (TIDBitmap *) PG_GETARG_POINTER(1); int64 ntids; ItemPointerData iptr; bool recheck; /* * Set up the scan keys, and check for unsatisfiable query. */ if (GinIsNewKey(scan)) ginNewScanKey(scan); if (GinIsVoidRes(scan)) PG_RETURN_INT64(0); ntids = 0; /* * First, scan the pending list and collect any matching entries into the * bitmap. After we scan a pending item, some other backend could post it * into the main index, and so we might visit it a second time during the * main scan. This is okay because we'll just re-set the same bit in the * bitmap. (The possibility of duplicate visits is a major reason why GIN * can't support the amgettuple API, however.) Note that it would not do * to scan the main index before the pending list, since concurrent * cleanup could then make us miss entries entirely. */ scanPendingInsert(scan, tbm, &ntids); /* * Now scan the main index. */ startScan(scan); ItemPointerSetMin(&iptr); for (;;) { CHECK_FOR_INTERRUPTS(); if (!scanGetItem(scan, &iptr, &iptr, &recheck)) break; if (ItemPointerIsLossyPage(&iptr)) tbm_add_page(tbm, ItemPointerGetBlockNumber(&iptr)); else tbm_add_tuples(tbm, &iptr, 1, recheck); ntids++; } PG_RETURN_INT64(ntids); }
void ginHeapTupleFastCollect | ( | GinState * | ginstate, | |
GinTupleCollector * | collector, | |||
OffsetNumber | attnum, | |||
Datum | value, | |||
bool | isNull, | |||
ItemPointer | ht_ctid | |||
) |
Definition at line 449 of file ginfast.c.
References ginExtractEntries(), GinFormTuple(), i, IndexTupleSize, GinTupleCollector::lentuples, tupleDesc::natts, GinTupleCollector::ntuples, NULL, GinState::origTupdesc, palloc(), repalloc(), GinTupleCollector::sumsize, IndexTupleData::t_tid, and GinTupleCollector::tuples.
Referenced by gininsert().
{ Datum *entries; GinNullCategory *categories; int32 i, nentries; /* * Extract the key values that need to be inserted in the index */ entries = ginExtractEntries(ginstate, attnum, value, isNull, &nentries, &categories); /* * Allocate/reallocate memory for storing collected tuples */ if (collector->tuples == NULL) { collector->lentuples = nentries * ginstate->origTupdesc->natts; collector->tuples = (IndexTuple *) palloc(sizeof(IndexTuple) * collector->lentuples); } while (collector->ntuples + nentries > collector->lentuples) { collector->lentuples *= 2; collector->tuples = (IndexTuple *) repalloc(collector->tuples, sizeof(IndexTuple) * collector->lentuples); } /* * Build an index tuple for each key value, and add to array. In pending * tuples we just stick the heap TID into t_tid. */ for (i = 0; i < nentries; i++) { IndexTuple itup; itup = GinFormTuple(ginstate, attnum, entries[i], categories[i], NULL, 0, true); itup->t_tid = *ht_ctid; collector->tuples[collector->ntuples++] = itup; collector->sumsize += IndexTupleSize(itup); } }
void ginHeapTupleFastInsert | ( | GinState * | ginstate, | |
GinTupleCollector * | collector | |||
) |
Definition at line 219 of file ginfast.c.
References Assert, XLogRecData::buffer, XLogRecData::buffer_std, BufferGetPage, XLogRecData::data, elog, END_CRIT_SECTION, ERROR, FirstOffsetNumber, GIN_EXCLUSIVE, GIN_METAPAGE_BLKNO, GIN_PAGE_FREESIZE, GIN_UNLOCK, ginInsertCleanup(), GinListPageSize, GinPageGetMeta, GinPageGetOpaque, GinMetaPageData::head, i, GinState::index, IndexTupleSize, InvalidBlockNumber, InvalidBuffer, InvalidOffsetNumber, XLogRecData::len, LockBuffer(), makeSublist(), MarkBufferDirty(), ginxlogUpdateMeta::metadata, ginxlogUpdateMeta::newRightlink, XLogRecData::next, ginxlogUpdateMeta::node, GinMetaPageData::nPendingHeapTuples, GinMetaPageData::nPendingPages, ginxlogUpdateMeta::ntuples, GinTupleCollector::ntuples, NULL, OffsetNumberNext, PageAddItem(), PageGetExactFreeSpace(), PageGetMaxOffsetNumber, PageIsEmpty, PageSetLSN, palloc(), ginxlogUpdateMeta::prevTail, RelationData::rd_node, ReadBuffer(), RelationGetRelationName, RelationNeedsWAL, START_CRIT_SECTION, GinTupleCollector::sumsize, GinMetaPageData::tail, GinMetaPageData::tailFreeSize, GinTupleCollector::tuples, UnlockReleaseBuffer(), work_mem, XLOG_GIN_UPDATE_META_PAGE, and XLogInsert().
Referenced by gininsert().
{ Relation index = ginstate->index; Buffer metabuffer; Page metapage; GinMetaPageData *metadata = NULL; XLogRecData rdata[2]; Buffer buffer = InvalidBuffer; Page page = NULL; ginxlogUpdateMeta data; bool separateList = false; bool needCleanup = false; if (collector->ntuples == 0) return; data.node = index->rd_node; data.ntuples = 0; data.newRightlink = data.prevTail = InvalidBlockNumber; rdata[0].buffer = InvalidBuffer; rdata[0].data = (char *) &data; rdata[0].len = sizeof(ginxlogUpdateMeta); rdata[0].next = NULL; metabuffer = ReadBuffer(index, GIN_METAPAGE_BLKNO); metapage = BufferGetPage(metabuffer); if (collector->sumsize + collector->ntuples * sizeof(ItemIdData) > GinListPageSize) { /* * Total size is greater than one page => make sublist */ separateList = true; } else { LockBuffer(metabuffer, GIN_EXCLUSIVE); metadata = GinPageGetMeta(metapage); if (metadata->head == InvalidBlockNumber || collector->sumsize + collector->ntuples * sizeof(ItemIdData) > metadata->tailFreeSize) { /* * Pending list is empty or total size is greater than freespace * on tail page => make sublist * * We unlock metabuffer to keep high concurrency */ separateList = true; LockBuffer(metabuffer, GIN_UNLOCK); } } if (separateList) { /* * We should make sublist separately and append it to the tail */ GinMetaPageData sublist; memset(&sublist, 0, sizeof(GinMetaPageData)); makeSublist(index, collector->tuples, collector->ntuples, &sublist); /* * metapage was unlocked, see above */ LockBuffer(metabuffer, GIN_EXCLUSIVE); metadata = GinPageGetMeta(metapage); if (metadata->head == InvalidBlockNumber) { /* * Main list is empty, so just insert sublist as main list */ START_CRIT_SECTION(); metadata->head = sublist.head; metadata->tail = sublist.tail; metadata->tailFreeSize = sublist.tailFreeSize; metadata->nPendingPages = sublist.nPendingPages; metadata->nPendingHeapTuples = sublist.nPendingHeapTuples; } else { /* * Merge lists */ data.prevTail = metadata->tail; data.newRightlink = sublist.head; buffer = ReadBuffer(index, metadata->tail); LockBuffer(buffer, GIN_EXCLUSIVE); page = BufferGetPage(buffer); rdata[0].next = rdata + 1; rdata[1].buffer = buffer; rdata[1].buffer_std = true; rdata[1].data = NULL; rdata[1].len = 0; rdata[1].next = NULL; Assert(GinPageGetOpaque(page)->rightlink == InvalidBlockNumber); START_CRIT_SECTION(); GinPageGetOpaque(page)->rightlink = sublist.head; MarkBufferDirty(buffer); metadata->tail = sublist.tail; metadata->tailFreeSize = sublist.tailFreeSize; metadata->nPendingPages += sublist.nPendingPages; metadata->nPendingHeapTuples += sublist.nPendingHeapTuples; } } else { /* * Insert into tail page. Metapage is already locked */ OffsetNumber l, off; int i, tupsize; char *ptr; buffer = ReadBuffer(index, metadata->tail); LockBuffer(buffer, GIN_EXCLUSIVE); page = BufferGetPage(buffer); off = (PageIsEmpty(page)) ? FirstOffsetNumber : OffsetNumberNext(PageGetMaxOffsetNumber(page)); rdata[0].next = rdata + 1; rdata[1].buffer = buffer; rdata[1].buffer_std = true; ptr = rdata[1].data = (char *) palloc(collector->sumsize); rdata[1].len = collector->sumsize; rdata[1].next = NULL; data.ntuples = collector->ntuples; START_CRIT_SECTION(); /* * Increase counter of heap tuples */ Assert(GinPageGetOpaque(page)->maxoff <= metadata->nPendingHeapTuples); GinPageGetOpaque(page)->maxoff++; metadata->nPendingHeapTuples++; for (i = 0; i < collector->ntuples; i++) { tupsize = IndexTupleSize(collector->tuples[i]); l = PageAddItem(page, (Item) collector->tuples[i], tupsize, off, false, false); if (l == InvalidOffsetNumber) elog(ERROR, "failed to add item to index page in \"%s\"", RelationGetRelationName(index)); memcpy(ptr, collector->tuples[i], tupsize); ptr += tupsize; off++; } Assert((ptr - rdata[1].data) <= collector->sumsize); metadata->tailFreeSize = PageGetExactFreeSpace(page); MarkBufferDirty(buffer); } /* * Write metabuffer, make xlog entry */ MarkBufferDirty(metabuffer); if (RelationNeedsWAL(index)) { XLogRecPtr recptr; memcpy(&data.metadata, metadata, sizeof(GinMetaPageData)); recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_UPDATE_META_PAGE, rdata); PageSetLSN(metapage, recptr); if (buffer != InvalidBuffer) { PageSetLSN(page, recptr); } } if (buffer != InvalidBuffer) UnlockReleaseBuffer(buffer); /* * Force pending list cleanup when it becomes too long. And, * ginInsertCleanup could take significant amount of time, so we prefer to * call it when it can do all the work in a single collection cycle. In * non-vacuum mode, it shouldn't require maintenance_work_mem, so fire it * while pending list is still small enough to fit into work_mem. * * ginInsertCleanup() should not be called inside our CRIT_SECTION. */ if (metadata->nPendingPages * GIN_PAGE_FREESIZE > work_mem * 1024L) needCleanup = true; UnlockReleaseBuffer(metabuffer); END_CRIT_SECTION(); if (needCleanup) ginInsertCleanup(ginstate, false, NULL); }
void ginInitBA | ( | BuildAccumulator * | accum | ) |
Definition at line 101 of file ginbulk.c.
References BuildAccumulator::allocatedMemory, cmpEntryAccumulator(), BuildAccumulator::eas_used, BuildAccumulator::entryallocator, ginAllocEntryAccumulator(), ginCombineData(), NULL, rb_create(), and BuildAccumulator::tree.
Referenced by ginbuild(), ginBuildCallback(), and ginInsertCleanup().
{ /* accum->ginstate is intentionally not set here */ accum->allocatedMemory = 0; accum->entryallocator = NULL; accum->eas_used = 0; accum->tree = rb_create(sizeof(GinEntryAccumulator), cmpEntryAccumulator, ginCombineData, ginAllocEntryAccumulator, NULL, /* no freefunc needed */ (void *) accum); }
Definition at line 250 of file ginutil.c.
References BufferGetPage, BufferGetPageSize, and GinInitPage().
Referenced by createPostingTree(), ginbuild(), ginbuildempty(), ginInsertValue(), ginRedoCreateIndex(), ginRedoCreatePTree(), ginRedoInsertListPage(), ginRedoSplit(), and writeListPage().
{ GinInitPage(BufferGetPage(b), f, BufferGetPageSize(b)); }
void GinInitMetabuffer | ( | Buffer | b | ) |
Definition at line 256 of file ginutil.c.
References BufferGetPage, BufferGetPageSize, GIN_META, GinInitPage(), GinPageGetMeta, GinMetaPageData::ginVersion, GinMetaPageData::head, GinMetaPageData::nDataPages, GinMetaPageData::nEntries, GinMetaPageData::nEntryPages, GinMetaPageData::nPendingHeapTuples, GinMetaPageData::nPendingPages, GinMetaPageData::nTotalPages, GinMetaPageData::tail, and GinMetaPageData::tailFreeSize.
Referenced by ginbuild(), ginbuildempty(), and ginRedoCreateIndex().
{ GinMetaPageData *metadata; Page page = BufferGetPage(b); GinInitPage(page, GIN_META, BufferGetPageSize(b)); metadata = GinPageGetMeta(page); metadata->head = metadata->tail = InvalidBlockNumber; metadata->tailFreeSize = 0; metadata->nPendingPages = 0; metadata->nPendingHeapTuples = 0; metadata->nTotalPages = 0; metadata->nEntryPages = 0; metadata->nDataPages = 0; metadata->nEntries = 0; metadata->ginVersion = GIN_CURRENT_VERSION; }
Definition at line 237 of file ginutil.c.
References GinPageOpaqueData::flags, GinPageGetOpaque, PageInit(), and GinPageOpaqueData::rightlink.
Referenced by dataSplitPage(), entrySplitPage(), GinInitBuffer(), and GinInitMetabuffer().
{ GinPageOpaque opaque; PageInit(page, pageSize, sizeof(GinPageOpaqueData)); opaque = GinPageGetOpaque(page); memset(opaque, 0, sizeof(GinPageOpaqueData)); opaque->flags = f; opaque->rightlink = InvalidBlockNumber; }
Datum gininsert | ( | PG_FUNCTION_ARGS | ) |
Definition at line 561 of file gininsert.c.
References ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE, ALLOCSET_DEFAULT_MINSIZE, AllocSetContextCreate(), CurrentMemoryContext, GinGetUseFastUpdate, ginHeapTupleFastCollect(), ginHeapTupleFastInsert(), ginHeapTupleInsert(), i, initGinState(), MemoryContextDelete(), MemoryContextSwitchTo(), tupleDesc::natts, GinState::origTupdesc, PG_GETARG_INT32, PG_GETARG_POINTER, PG_RETURN_BOOL, and values.
{ Relation index = (Relation) PG_GETARG_POINTER(0); Datum *values = (Datum *) PG_GETARG_POINTER(1); bool *isnull = (bool *) PG_GETARG_POINTER(2); ItemPointer ht_ctid = (ItemPointer) PG_GETARG_POINTER(3); #ifdef NOT_USED Relation heapRel = (Relation) PG_GETARG_POINTER(4); IndexUniqueCheck checkUnique = (IndexUniqueCheck) PG_GETARG_INT32(5); #endif GinState ginstate; MemoryContext oldCtx; MemoryContext insertCtx; int i; insertCtx = AllocSetContextCreate(CurrentMemoryContext, "Gin insert temporary context", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); oldCtx = MemoryContextSwitchTo(insertCtx); initGinState(&ginstate, index); if (GinGetUseFastUpdate(index)) { GinTupleCollector collector; memset(&collector, 0, sizeof(GinTupleCollector)); for (i = 0; i < ginstate.origTupdesc->natts; i++) ginHeapTupleFastCollect(&ginstate, &collector, (OffsetNumber) (i + 1), values[i], isnull[i], ht_ctid); ginHeapTupleFastInsert(&ginstate, &collector); } else { for (i = 0; i < ginstate.origTupdesc->natts; i++) ginHeapTupleInsert(&ginstate, (OffsetNumber) (i + 1), values[i], isnull[i], ht_ctid); } MemoryContextSwitchTo(oldCtx); MemoryContextDelete(insertCtx); PG_RETURN_BOOL(false); }
void ginInsertBAEntries | ( | BuildAccumulator * | accum, | |
ItemPointer | heapptr, | |||
OffsetNumber | attnum, | |||
Datum * | entries, | |||
GinNullCategory * | categories, | |||
int32 | nentries | |||
) |
Definition at line 201 of file ginbulk.c.
References Assert, FirstOffsetNumber, ginInsertBAEntry(), i, and ItemPointerIsValid.
Referenced by ginHeapTupleBulkInsert(), and processPendingPage().
{ uint32 step = nentries; if (nentries <= 0) return; Assert(ItemPointerIsValid(heapptr) && attnum >= FirstOffsetNumber); /* * step will contain largest power of 2 and <= nentries */ step |= (step >> 1); step |= (step >> 2); step |= (step >> 4); step |= (step >> 8); step |= (step >> 16); step >>= 1; step++; while (step > 0) { int i; for (i = step - 1; i < nentries && i >= 0; i += step << 1 /* *2 */ ) ginInsertBAEntry(accum, heapptr, attnum, entries[i], categories[i]); step >>= 1; /* /2 */ } }
void ginInsertCleanup | ( | GinState * | ginstate, | |
bool | vac_delay, | |||
IndexBulkDeleteResult * | stats | |||
) |
Definition at line 727 of file ginfast.c.
References BuildAccumulator::allocatedMemory, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE, ALLOCSET_DEFAULT_MINSIZE, AllocSetContextCreate(), Assert, BufferGetPage, CHECK_FOR_INTERRUPTS, CurrentMemoryContext, FirstOffsetNumber, GIN_EXCLUSIVE, GIN_METAPAGE_BLKNO, GIN_SHARE, GIN_UNLOCK, ginBeginBAScan(), ginEntryInsert(), ginGetBAEntry(), ginInitBA(), GinPageGetMeta, GinPageGetOpaque, GinPageHasFullRow, GinPageIsDeleted, BuildAccumulator::ginstate, GinMetaPageData::head, GinState::index, initKeyArray(), InvalidBlockNumber, sort-test::list, LockBuffer(), maintenance_work_mem, KeyArray::maxvalues, MemoryContextDelete(), MemoryContextReset(), MemoryContextSwitchTo(), NULL, opCtx, PageGetMaxOffsetNumber, processPendingPage(), ReadBuffer(), ReleaseBuffer(), shiftList(), UnlockReleaseBuffer(), and vacuum_delay_point().
Referenced by ginbulkdelete(), ginHeapTupleFastInsert(), and ginvacuumcleanup().
{ Relation index = ginstate->index; Buffer metabuffer, buffer; Page metapage, page; GinMetaPageData *metadata; MemoryContext opCtx, oldCtx; BuildAccumulator accum; KeyArray datums; BlockNumber blkno; metabuffer = ReadBuffer(index, GIN_METAPAGE_BLKNO); LockBuffer(metabuffer, GIN_SHARE); metapage = BufferGetPage(metabuffer); metadata = GinPageGetMeta(metapage); if (metadata->head == InvalidBlockNumber) { /* Nothing to do */ UnlockReleaseBuffer(metabuffer); return; } /* * Read and lock head of pending list */ blkno = metadata->head; buffer = ReadBuffer(index, blkno); LockBuffer(buffer, GIN_SHARE); page = BufferGetPage(buffer); LockBuffer(metabuffer, GIN_UNLOCK); /* * Initialize. All temporary space will be in opCtx */ opCtx = AllocSetContextCreate(CurrentMemoryContext, "GIN insert cleanup temporary context", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); oldCtx = MemoryContextSwitchTo(opCtx); initKeyArray(&datums, 128); ginInitBA(&accum); accum.ginstate = ginstate; /* * At the top of this loop, we have pin and lock on the current page of * the pending list. However, we'll release that before exiting the loop. * Note we also have pin but not lock on the metapage. */ for (;;) { if (GinPageIsDeleted(page)) { /* another cleanup process is running concurrently */ UnlockReleaseBuffer(buffer); break; } /* * read page's datums into accum */ processPendingPage(&accum, &datums, page, FirstOffsetNumber); if (vac_delay) vacuum_delay_point(); /* * Is it time to flush memory to disk? Flush if we are at the end of * the pending list, or if we have a full row and memory is getting * full. * * XXX using up maintenance_work_mem here is probably unreasonably * much, since vacuum might already be using that much. */ if (GinPageGetOpaque(page)->rightlink == InvalidBlockNumber || (GinPageHasFullRow(page) && (accum.allocatedMemory >= maintenance_work_mem * 1024L))) { ItemPointerData *list; uint32 nlist; Datum key; GinNullCategory category; OffsetNumber maxoff, attnum; /* * Unlock current page to increase performance. Changes of page * will be checked later by comparing maxoff after completion of * memory flush. */ maxoff = PageGetMaxOffsetNumber(page); LockBuffer(buffer, GIN_UNLOCK); /* * Moving collected data into regular structure can take * significant amount of time - so, run it without locking pending * list. */ ginBeginBAScan(&accum); while ((list = ginGetBAEntry(&accum, &attnum, &key, &category, &nlist)) != NULL) { ginEntryInsert(ginstate, attnum, key, category, list, nlist, NULL); if (vac_delay) vacuum_delay_point(); } /* * Lock the whole list to remove pages */ LockBuffer(metabuffer, GIN_EXCLUSIVE); LockBuffer(buffer, GIN_SHARE); if (GinPageIsDeleted(page)) { /* another cleanup process is running concurrently */ UnlockReleaseBuffer(buffer); LockBuffer(metabuffer, GIN_UNLOCK); break; } /* * While we left the page unlocked, more stuff might have gotten * added to it. If so, process those entries immediately. There * shouldn't be very many, so we don't worry about the fact that * we're doing this with exclusive lock. Insertion algorithm * guarantees that inserted row(s) will not continue on next page. * NOTE: intentionally no vacuum_delay_point in this loop. */ if (PageGetMaxOffsetNumber(page) != maxoff) { ginInitBA(&accum); processPendingPage(&accum, &datums, page, maxoff + 1); ginBeginBAScan(&accum); while ((list = ginGetBAEntry(&accum, &attnum, &key, &category, &nlist)) != NULL) ginEntryInsert(ginstate, attnum, key, category, list, nlist, NULL); } /* * Remember next page - it will become the new list head */ blkno = GinPageGetOpaque(page)->rightlink; UnlockReleaseBuffer(buffer); /* shiftList will do exclusive * locking */ /* * remove readed pages from pending list, at this point all * content of readed pages is in regular structure */ if (shiftList(index, metabuffer, blkno, stats)) { /* another cleanup process is running concurrently */ LockBuffer(metabuffer, GIN_UNLOCK); break; } Assert(blkno == metadata->head); LockBuffer(metabuffer, GIN_UNLOCK); /* * if we removed the whole pending list just exit */ if (blkno == InvalidBlockNumber) break; /* * release memory used so far and reinit state */ MemoryContextReset(opCtx); initKeyArray(&datums, datums.maxvalues); ginInitBA(&accum); } else { blkno = GinPageGetOpaque(page)->rightlink; UnlockReleaseBuffer(buffer); } /* * Read next page in pending list */ CHECK_FOR_INTERRUPTS(); buffer = ReadBuffer(index, blkno); LockBuffer(buffer, GIN_SHARE); page = BufferGetPage(buffer); } ReleaseBuffer(metabuffer); /* Clean up temporary space */ MemoryContextSwitchTo(oldCtx); MemoryContextDelete(opCtx); }
void ginInsertItemPointers | ( | GinPostingTreeScan * | gdi, | |
ItemPointerData * | items, | |||
uint32 | nitem, | |||
GinStatsData * | buildStats | |||
) |
Definition at line 648 of file gindatapage.c.
References GinBtreeStack::blkno, GinPostingTreeScan::btree, GinBtreeStack::buffer, GinBtreeData::curitem, GinBtreeData::findItem, freeGinBtreeStack(), GIN_UNLOCK, ginFindLeafPage(), ginInsertValue(), ginPrepareFindLeafPage(), GinBtreeData::items, LockBuffer(), GinBtreeData::nitem, and GinPostingTreeScan::stack.
Referenced by addItemPointersToLeafTuple(), buildFreshLeafTuple(), and ginEntryInsert().
{ BlockNumber rootBlkno = gdi->stack->blkno; gdi->btree.items = items; gdi->btree.nitem = nitem; gdi->btree.curitem = 0; while (gdi->btree.curitem < gdi->btree.nitem) { if (!gdi->stack) gdi->stack = ginPrepareFindLeafPage(&gdi->btree, rootBlkno); gdi->stack = ginFindLeafPage(&gdi->btree, gdi->stack); if (gdi->btree.findItem(&(gdi->btree), gdi->stack)) { /* * gdi->btree.items[gdi->btree.curitem] already exists in index */ gdi->btree.curitem++; LockBuffer(gdi->stack->buffer, GIN_UNLOCK); freeGinBtreeStack(gdi->stack); } else ginInsertValue(&(gdi->btree), gdi->stack, buildStats); gdi->stack = NULL; } }
void ginInsertValue | ( | GinBtree | btree, | |
GinBtreeStack * | stack, | |||
GinStatsData * | buildStats | |||
) |
Definition at line 273 of file ginbtree.c.
References Assert, GinBtreeStack::blkno, BlockNumberIsValid, GinBtreeStack::buffer, BufferGetBlockNumber(), BufferGetPage, XLogRecData::data, END_CRIT_SECTION, FALSE, GinBtreeData::fillRoot, GinBtreeData::findChildPtr, freeGinBtreeStack(), GIN_EXCLUSIVE, GIN_LEAF, GIN_UNLOCK, ginFindParents(), GinInitBuffer(), GinNewBuffer(), GinPageGetOpaque, GinBtreeData::index, InvalidBlockNumber, InvalidOffsetNumber, GinBtreeData::isData, GinBtreeData::isDelete, GinBtreeData::isEnoughSpace, LockBuffer(), MarkBufferDirty(), GinStatsData::nDataPages, GinStatsData::nEntryPages, NULL, GinBtreeStack::off, PageRestoreTempPage(), PageSetLSN, GinBtreeStack::parent, pfree(), GinBtreeData::placeToPage, RelationNeedsWAL, ReleaseAndReadBuffer(), GinBtreeData::splitPage, START_CRIT_SECTION, TRUE, UnlockReleaseBuffer(), XLOG_GIN_INSERT, XLOG_GIN_SPLIT, and XLogInsert().
Referenced by ginContinueSplit(), ginEntryInsert(), and ginInsertItemPointers().
{ GinBtreeStack *parent; BlockNumber rootBlkno; Page page, rpage, lpage; /* extract root BlockNumber from stack */ Assert(stack != NULL); parent = stack; while (parent->parent) parent = parent->parent; rootBlkno = parent->blkno; Assert(BlockNumberIsValid(rootBlkno)); /* this loop crawls up the stack until the insertion is complete */ for (;;) { XLogRecData *rdata; BlockNumber savedRightLink; page = BufferGetPage(stack->buffer); savedRightLink = GinPageGetOpaque(page)->rightlink; if (btree->isEnoughSpace(btree, stack->buffer, stack->off)) { START_CRIT_SECTION(); btree->placeToPage(btree, stack->buffer, stack->off, &rdata); MarkBufferDirty(stack->buffer); if (RelationNeedsWAL(btree->index)) { XLogRecPtr recptr; recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_INSERT, rdata); PageSetLSN(page, recptr); } LockBuffer(stack->buffer, GIN_UNLOCK); END_CRIT_SECTION(); freeGinBtreeStack(stack); return; } else { Buffer rbuffer = GinNewBuffer(btree->index); Page newlpage; /* * newlpage is a pointer to memory page, it doesn't associate with * buffer, stack->buffer should be untouched */ newlpage = btree->splitPage(btree, stack->buffer, rbuffer, stack->off, &rdata); ((ginxlogSplit *) (rdata->data))->rootBlkno = rootBlkno; /* During index build, count the newly-split page */ if (buildStats) { if (btree->isData) buildStats->nDataPages++; else buildStats->nEntryPages++; } parent = stack->parent; if (parent == NULL) { /* * split root, so we need to allocate new left page and place * pointer on root to left and right page */ Buffer lbuffer = GinNewBuffer(btree->index); ((ginxlogSplit *) (rdata->data))->isRootSplit = TRUE; ((ginxlogSplit *) (rdata->data))->rrlink = InvalidBlockNumber; page = BufferGetPage(stack->buffer); lpage = BufferGetPage(lbuffer); rpage = BufferGetPage(rbuffer); GinPageGetOpaque(rpage)->rightlink = InvalidBlockNumber; GinPageGetOpaque(newlpage)->rightlink = BufferGetBlockNumber(rbuffer); ((ginxlogSplit *) (rdata->data))->lblkno = BufferGetBlockNumber(lbuffer); START_CRIT_SECTION(); GinInitBuffer(stack->buffer, GinPageGetOpaque(newlpage)->flags & ~GIN_LEAF); PageRestoreTempPage(newlpage, lpage); btree->fillRoot(btree, stack->buffer, lbuffer, rbuffer); MarkBufferDirty(rbuffer); MarkBufferDirty(lbuffer); MarkBufferDirty(stack->buffer); if (RelationNeedsWAL(btree->index)) { XLogRecPtr recptr; recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_SPLIT, rdata); PageSetLSN(page, recptr); PageSetLSN(lpage, recptr); PageSetLSN(rpage, recptr); } UnlockReleaseBuffer(rbuffer); UnlockReleaseBuffer(lbuffer); LockBuffer(stack->buffer, GIN_UNLOCK); END_CRIT_SECTION(); freeGinBtreeStack(stack); /* During index build, count the newly-added root page */ if (buildStats) { if (btree->isData) buildStats->nDataPages++; else buildStats->nEntryPages++; } return; } else { /* split non-root page */ ((ginxlogSplit *) (rdata->data))->isRootSplit = FALSE; ((ginxlogSplit *) (rdata->data))->rrlink = savedRightLink; lpage = BufferGetPage(stack->buffer); rpage = BufferGetPage(rbuffer); GinPageGetOpaque(rpage)->rightlink = savedRightLink; GinPageGetOpaque(newlpage)->rightlink = BufferGetBlockNumber(rbuffer); START_CRIT_SECTION(); PageRestoreTempPage(newlpage, lpage); MarkBufferDirty(rbuffer); MarkBufferDirty(stack->buffer); if (RelationNeedsWAL(btree->index)) { XLogRecPtr recptr; recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_SPLIT, rdata); PageSetLSN(lpage, recptr); PageSetLSN(rpage, recptr); } UnlockReleaseBuffer(rbuffer); END_CRIT_SECTION(); } } btree->isDelete = FALSE; /* search parent to lock */ LockBuffer(parent->buffer, GIN_EXCLUSIVE); /* move right if it's needed */ page = BufferGetPage(parent->buffer); while ((parent->off = btree->findChildPtr(btree, page, stack->blkno, parent->off)) == InvalidOffsetNumber) { BlockNumber rightlink = GinPageGetOpaque(page)->rightlink; LockBuffer(parent->buffer, GIN_UNLOCK); if (rightlink == InvalidBlockNumber) { /* * rightmost page, but we don't find parent, we should use * plain search... */ ginFindParents(btree, stack, rootBlkno); parent = stack->parent; Assert(parent != NULL); break; } parent->blkno = rightlink; parent->buffer = ReleaseAndReadBuffer(parent->buffer, btree->index, parent->blkno); LockBuffer(parent->buffer, GIN_EXCLUSIVE); page = BufferGetPage(parent->buffer); } UnlockReleaseBuffer(stack->buffer); pfree(stack); stack = parent; } }
Datum ginmarkpos | ( | PG_FUNCTION_ARGS | ) |
Definition at line 445 of file ginscan.c.
References elog, ERROR, and PG_RETURN_VOID.
{ elog(ERROR, "GIN does not support mark/restore"); PG_RETURN_VOID(); }
uint32 ginMergeItemPointers | ( | ItemPointerData * | dst, | |
ItemPointerData * | a, | |||
uint32 | na, | |||
ItemPointerData * | b, | |||
uint32 | nb | |||
) |
Definition at line 45 of file gindatapage.c.
References cmp(), and ginCompareItemPointers().
Referenced by addItemPointersToLeafTuple().
{ ItemPointerData *dptr = dst; ItemPointerData *aptr = a, *bptr = b; while (aptr - a < na && bptr - b < nb) { int cmp = ginCompareItemPointers(aptr, bptr); if (cmp > 0) *dptr++ = *bptr++; else if (cmp == 0) { /* we want only one copy of the identical items */ *dptr++ = *bptr++; aptr++; } else *dptr++ = *aptr++; } while (aptr - a < na) *dptr++ = *aptr++; while (bptr - b < nb) *dptr++ = *bptr++; return dptr - dst; }
Definition at line 186 of file ginutil.c.
References BufferGetPage, ConditionalLockBuffer(), ExclusiveLock, GetFreeIndexPage(), GIN_EXCLUSIVE, GIN_UNLOCK, GinPageIsDeleted, InvalidBlockNumber, LockBuffer(), LockRelationForExtension(), P_NEW, PageIsNew, ReadBuffer(), RELATION_IS_LOCAL, ReleaseBuffer(), and UnlockRelationForExtension().
Referenced by createPostingTree(), ginbuild(), ginInsertValue(), and makeSublist().
{ Buffer buffer; bool needLock; /* First, try to get a page from FSM */ for (;;) { BlockNumber blkno = GetFreeIndexPage(index); if (blkno == InvalidBlockNumber) break; buffer = ReadBuffer(index, blkno); /* * We have to guard against the possibility that someone else already * recycled this page; the buffer may be locked if so. */ if (ConditionalLockBuffer(buffer)) { Page page = BufferGetPage(buffer); if (PageIsNew(page)) return buffer; /* OK to use, if never initialized */ if (GinPageIsDeleted(page)) return buffer; /* OK to use */ LockBuffer(buffer, GIN_UNLOCK); } /* Can't use it, so release buffer and try again */ ReleaseBuffer(buffer); } /* Must extend the file */ needLock = !RELATION_IS_LOCAL(index); if (needLock) LockRelationForExtension(index, ExclusiveLock); buffer = ReadBuffer(index, P_NEW); LockBuffer(buffer, GIN_EXCLUSIVE); if (needLock) UnlockRelationForExtension(index, ExclusiveLock); return buffer; }
void ginNewScanKey | ( | IndexScanDesc | scan | ) |
Definition at line 265 of file ginscan.c.
References GinScanOpaqueData::allocentries, DatumGetPointer, GinScanOpaqueData::entries, ereport, errcode(), errhint(), errmsg(), ERROR, GinState::extractQueryFn, FirstOffsetNumber, FunctionCall7Coll(), GIN_SEARCH_MODE_ALL, GIN_SEARCH_MODE_DEFAULT, GIN_SEARCH_MODE_EVERYTHING, ginFillScanKey(), ginGetStats(), GinScanOpaqueData::ginstate, GinStatsData::ginVersion, i, IndexScanDescData::indexRelation, InvalidStrategy, GinScanOpaqueData::isVoidRes, IndexScanDescData::keyData, GinScanOpaqueData::keys, Max, GinScanOpaqueData::nkeys, NULL, IndexScanDescData::numberOfKeys, IndexScanDescData::opaque, palloc(), palloc0(), pgstat_count_index_scan, PointerGetDatum, RelationGetRelationName, ScanKeyData::sk_argument, ScanKeyData::sk_attno, ScanKeyData::sk_flags, SK_ISNULL, ScanKeyData::sk_strategy, GinState::supportCollation, GinScanOpaqueData::totalentries, and UInt16GetDatum.
Referenced by gingetbitmap().
{ ScanKey scankey = scan->keyData; GinScanOpaque so = (GinScanOpaque) scan->opaque; int i; bool hasNullQuery = false; /* if no scan keys provided, allocate extra EVERYTHING GinScanKey */ so->keys = (GinScanKey) palloc(Max(scan->numberOfKeys, 1) * sizeof(GinScanKeyData)); so->nkeys = 0; /* initialize expansible array of GinScanEntry pointers */ so->totalentries = 0; so->allocentries = 32; so->entries = (GinScanEntry *) palloc0(so->allocentries * sizeof(GinScanEntry)); so->isVoidRes = false; for (i = 0; i < scan->numberOfKeys; i++) { ScanKey skey = &scankey[i]; Datum *queryValues; int32 nQueryValues = 0; bool *partial_matches = NULL; Pointer *extra_data = NULL; bool *nullFlags = NULL; int32 searchMode = GIN_SEARCH_MODE_DEFAULT; /* * We assume that GIN-indexable operators are strict, so a null query * argument means an unsatisfiable query. */ if (skey->sk_flags & SK_ISNULL) { so->isVoidRes = true; break; } /* OK to call the extractQueryFn */ queryValues = (Datum *) DatumGetPointer(FunctionCall7Coll(&so->ginstate.extractQueryFn[skey->sk_attno - 1], so->ginstate.supportCollation[skey->sk_attno - 1], skey->sk_argument, PointerGetDatum(&nQueryValues), UInt16GetDatum(skey->sk_strategy), PointerGetDatum(&partial_matches), PointerGetDatum(&extra_data), PointerGetDatum(&nullFlags), PointerGetDatum(&searchMode))); /* * If bogus searchMode is returned, treat as GIN_SEARCH_MODE_ALL; note * in particular we don't allow extractQueryFn to select * GIN_SEARCH_MODE_EVERYTHING. */ if (searchMode < GIN_SEARCH_MODE_DEFAULT || searchMode > GIN_SEARCH_MODE_ALL) searchMode = GIN_SEARCH_MODE_ALL; /* Non-default modes require the index to have placeholders */ if (searchMode != GIN_SEARCH_MODE_DEFAULT) hasNullQuery = true; /* * In default mode, no keys means an unsatisfiable query. */ if (queryValues == NULL || nQueryValues <= 0) { if (searchMode == GIN_SEARCH_MODE_DEFAULT) { so->isVoidRes = true; break; } nQueryValues = 0; /* ensure sane value */ } /* * If the extractQueryFn didn't create a nullFlags array, create one, * assuming that everything's non-null. Otherwise, run through the * array and make sure each value is exactly 0 or 1; this ensures * binary compatibility with the GinNullCategory representation. While * at it, detect whether any null keys are present. */ if (nullFlags == NULL) nullFlags = (bool *) palloc0(nQueryValues * sizeof(bool)); else { int32 j; for (j = 0; j < nQueryValues; j++) { if (nullFlags[j]) { nullFlags[j] = true; /* not any other nonzero value */ hasNullQuery = true; } } } /* now we can use the nullFlags as category codes */ ginFillScanKey(so, skey->sk_attno, skey->sk_strategy, searchMode, skey->sk_argument, nQueryValues, queryValues, (GinNullCategory *) nullFlags, partial_matches, extra_data); } /* * If there are no regular scan keys, generate an EVERYTHING scankey to * drive a full-index scan. */ if (so->nkeys == 0 && !so->isVoidRes) { hasNullQuery = true; ginFillScanKey(so, FirstOffsetNumber, InvalidStrategy, GIN_SEARCH_MODE_EVERYTHING, (Datum) 0, 0, NULL, NULL, NULL, NULL); } /* * If the index is version 0, it may be missing null and placeholder * entries, which would render searches for nulls and full-index scans * unreliable. Throw an error if so. */ if (hasNullQuery && !so->isVoidRes) { GinStatsData ginStats; ginGetStats(scan->indexRelation, &ginStats); if (ginStats.ginVersion < 1) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("old GIN indexes do not support whole-index scans nor searches for nulls"), errhint("To fix this, do REINDEX INDEX \"%s\".", RelationGetRelationName(scan->indexRelation)))); } pgstat_count_index_scan(scan->indexRelation); }
Datum ginoptions | ( | PG_FUNCTION_ARGS | ) |
Definition at line 496 of file ginutil.c.
References allocateReloptStruct(), fillRelOptions(), lengthof, offsetof, parseRelOptions(), pfree(), PG_GETARG_BOOL, PG_GETARG_DATUM, PG_RETURN_BYTEA_P, PG_RETURN_NULL, and RELOPT_KIND_GIN.
{ Datum reloptions = PG_GETARG_DATUM(0); bool validate = PG_GETARG_BOOL(1); relopt_value *options; GinOptions *rdopts; int numoptions; static const relopt_parse_elt tab[] = { {"fastupdate", RELOPT_TYPE_BOOL, offsetof(GinOptions, useFastUpdate)} }; options = parseRelOptions(reloptions, validate, RELOPT_KIND_GIN, &numoptions); /* if none set, we're done */ if (numoptions == 0) PG_RETURN_NULL(); rdopts = allocateReloptStruct(sizeof(GinOptions), options, numoptions); fillRelOptions((void *) rdopts, sizeof(GinOptions), options, numoptions, validate, tab, lengthof(tab)); pfree(options); PG_RETURN_BYTEA_P(rdopts); }
void GinPageDeletePostingItem | ( | Page | page, | |
OffsetNumber | offset | |||
) |
Definition at line 308 of file gindatapage.c.
References Assert, FirstOffsetNumber, GinDataPageGetItem, GinPageGetOpaque, GinPageIsLeaf, and memmove.
Referenced by ginDeletePage(), and ginRedoDeletePage().
{ OffsetNumber maxoff = GinPageGetOpaque(page)->maxoff; Assert(!GinPageIsLeaf(page)); Assert(offset >= FirstOffsetNumber && offset <= maxoff); if (offset != maxoff) memmove(GinDataPageGetItem(page, offset), GinDataPageGetItem(page, offset + 1), sizeof(PostingItem) * (maxoff - offset)); GinPageGetOpaque(page)->maxoff--; }
IndexTuple ginPageGetLinkItup | ( | Buffer | buf | ) |
Definition at line 665 of file ginentrypage.c.
References BufferGetBlockNumber(), BufferGetPage, getRightMostTuple(), and GinFormInteriorTuple().
Referenced by ginContinueSplit(), and ginEntryFillRoot().
{ IndexTuple itup, nitup; Page page = BufferGetPage(buf); itup = getRightMostTuple(page); nitup = GinFormInteriorTuple(itup, page, BufferGetBlockNumber(buf)); return nitup; }
Definition at line 606 of file gindatapage.c.
References GinBtreeData::fillRoot, GinBtreeData::findChildPage, GinBtreeData::findChildPtr, GinBtreeData::findItem, GinBtreeData::fullScan, GinBtreeData::getLeftMostPage, GinBtreeData::index, GinBtreeData::isBuild, GinBtreeData::isData, GinBtreeData::isDelete, GinBtreeData::isEnoughSpace, GinBtreeData::isMoveRight, GinBtreeData::placeToPage, GinBtreeData::searchMode, and GinBtreeData::splitPage.
Referenced by ginContinueSplit(), and ginPrepareScanPostingTree().
{ memset(btree, 0, sizeof(GinBtreeData)); btree->index = index; btree->findChildPage = dataLocateItem; btree->isMoveRight = dataIsMoveRight; btree->findItem = dataLocateLeafItem; btree->findChildPtr = dataFindChildPtr; btree->getLeftMostPage = dataGetLeftMostPage; btree->isEnoughSpace = dataIsEnoughSpace; btree->placeToPage = dataPlaceToPage; btree->splitPage = dataSplitPage; btree->fillRoot = ginDataFillRoot; btree->isData = TRUE; btree->searchMode = FALSE; btree->isDelete = FALSE; btree->fullScan = FALSE; btree->isBuild = FALSE; }
void ginPrepareEntryScan | ( | GinBtree | btree, | |
OffsetNumber | attnum, | |||
Datum | key, | |||
GinNullCategory | category, | |||
GinState * | ginstate | |||
) |
Definition at line 707 of file ginentrypage.c.
References GinBtreeData::entryAttnum, GinBtreeData::entryCategory, GinBtreeData::entryKey, GinBtreeData::fillRoot, GinBtreeData::findChildPage, GinBtreeData::findChildPtr, GinBtreeData::findItem, GinBtreeData::fullScan, GinBtreeData::getLeftMostPage, GinBtreeData::ginstate, GinState::index, GinBtreeData::index, GinBtreeData::isBuild, GinBtreeData::isData, GinBtreeData::isDelete, GinBtreeData::isEnoughSpace, GinBtreeData::isMoveRight, GinBtreeData::placeToPage, GinBtreeData::searchMode, and GinBtreeData::splitPage.
Referenced by ginContinueSplit(), ginEntryInsert(), and startScanEntry().
{ memset(btree, 0, sizeof(GinBtreeData)); btree->index = ginstate->index; btree->ginstate = ginstate; btree->findChildPage = entryLocateEntry; btree->isMoveRight = entryIsMoveRight; btree->findItem = entryLocateLeafEntry; btree->findChildPtr = entryFindChildPtr; btree->getLeftMostPage = entryGetLeftMostPage; btree->isEnoughSpace = entryIsEnoughSpace; btree->placeToPage = entryPlaceToPage; btree->splitPage = entrySplitPage; btree->fillRoot = ginEntryFillRoot; btree->isData = FALSE; btree->searchMode = FALSE; btree->fullScan = FALSE; btree->isBuild = FALSE; btree->entryAttnum = attnum; btree->entryKey = key; btree->entryCategory = category; btree->isDelete = FALSE; }
GinBtreeStack* ginPrepareFindLeafPage | ( | GinBtree | btree, | |
BlockNumber | blkno | |||
) |
Definition at line 56 of file ginbtree.c.
References GinBtreeStack::blkno, GinBtreeStack::buffer, ginTraverseLock(), GinBtreeData::index, palloc(), GinBtreeStack::parent, GinBtreeStack::predictNumber, ReadBuffer(), and GinBtreeData::searchMode.
Referenced by ginFindLeafPage(), ginInsertItemPointers(), and ginPrepareScanPostingTree().
{ GinBtreeStack *stack = (GinBtreeStack *) palloc(sizeof(GinBtreeStack)); stack->blkno = blkno; stack->buffer = ReadBuffer(btree->index, stack->blkno); stack->parent = NULL; stack->predictNumber = 1; ginTraverseLock(stack->buffer, btree->searchMode); return stack; }
GinPostingTreeScan* ginPrepareScanPostingTree | ( | Relation | index, | |
BlockNumber | rootBlkno, | |||
bool | searchMode | |||
) |
Definition at line 630 of file gindatapage.c.
References GinPostingTreeScan::btree, GinBtreeData::fullScan, ginPrepareDataScan(), ginPrepareFindLeafPage(), palloc0(), GinBtreeData::searchMode, and GinPostingTreeScan::stack.
Referenced by addItemPointersToLeafTuple(), buildFreshLeafTuple(), ginEntryInsert(), scanPostingTree(), and startScanEntry().
{ GinPostingTreeScan *gdi = (GinPostingTreeScan *) palloc0(sizeof(GinPostingTreeScan)); ginPrepareDataScan(&gdi->btree, index); gdi->btree.searchMode = searchMode; gdi->btree.fullScan = searchMode; gdi->stack = ginPrepareFindLeafPage(&gdi->btree, rootBlkno); return gdi; }
Datum ginrescan | ( | PG_FUNCTION_ARGS | ) |
Definition at line 409 of file ginscan.c.
References freeScanKeys(), IndexScanDescData::keyData, memmove, IndexScanDescData::numberOfKeys, IndexScanDescData::opaque, PG_GETARG_POINTER, and PG_RETURN_VOID.
{ IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0); ScanKey scankey = (ScanKey) PG_GETARG_POINTER(1); /* remaining arguments are ignored */ GinScanOpaque so = (GinScanOpaque) scan->opaque; freeScanKeys(so); if (scankey && scan->numberOfKeys > 0) { memmove(scan->keyData, scankey, scan->numberOfKeys * sizeof(ScanKeyData)); } PG_RETURN_VOID(); }
Datum ginrestrpos | ( | PG_FUNCTION_ARGS | ) |
Definition at line 452 of file ginscan.c.
References elog, ERROR, and PG_RETURN_VOID.
{ elog(ERROR, "GIN does not support mark/restore"); PG_RETURN_VOID(); }
Buffer ginScanBeginPostingTree | ( | GinPostingTreeScan * | gdi | ) |
Definition at line 682 of file gindatapage.c.
References GinPostingTreeScan::btree, GinBtreeStack::buffer, ginFindLeafPage(), and GinPostingTreeScan::stack.
Referenced by scanPostingTree(), and startScanEntry().
void GinShortenTuple | ( | IndexTuple | itup, | |
uint32 | nipd | |||
) |
Definition at line 145 of file ginentrypage.c.
References Assert, GinGetNPosting, GinGetPostingOffset, GinSetNPosting, INDEX_SIZE_MASK, MAXALIGN, and IndexTupleData::t_info.
Referenced by addItemPointersToLeafTuple().
{ uint32 newsize; Assert(nipd <= GinGetNPosting(itup)); newsize = GinGetPostingOffset(itup) + sizeof(ItemPointerData) * nipd; newsize = MAXALIGN(newsize); Assert(newsize <= (itup->t_info & INDEX_SIZE_MASK)); itup->t_info &= ~INDEX_SIZE_MASK; itup->t_info |= newsize; GinSetNPosting(itup, nipd); }
OffsetNumber gintuple_get_attrnum | ( | GinState * | ginstate, | |
IndexTuple | tuple | |||
) |
Definition at line 112 of file ginutil.c.
References Assert, DatumGetUInt16, FirstOffsetNumber, index_getattr, GinState::oneCol, and GinState::tupdesc.
Referenced by addItemPointersToLeafTuple(), collectMatchBitmap(), collectMatchesForHeapRow(), entryIsMoveRight(), entryLocateEntry(), entryLocateLeafEntry(), gintuple_get_key(), ginVacuumEntryPage(), matchPartialInPendingList(), and processPendingPage().
{ OffsetNumber colN; if (ginstate->oneCol) { /* column number is not stored explicitly */ colN = FirstOffsetNumber; } else { Datum res; bool isnull; /* * First attribute is always int16, so we can safely use any tuple * descriptor to obtain first attribute of tuple */ res = index_getattr(tuple, FirstOffsetNumber, ginstate->tupdesc[0], &isnull); Assert(!isnull); colN = DatumGetUInt16(res); Assert(colN >= FirstOffsetNumber && colN <= ginstate->origTupdesc->natts); } return colN; }
Datum gintuple_get_key | ( | GinState * | ginstate, | |
IndexTuple | tuple, | |||
GinNullCategory * | category | |||
) |
Definition at line 145 of file ginutil.c.
References FirstOffsetNumber, GinGetNullCategory, gintuple_get_attrnum(), index_getattr, OffsetNumberNext, GinState::oneCol, GinState::origTupdesc, and GinState::tupdesc.
Referenced by addItemPointersToLeafTuple(), collectMatchBitmap(), collectMatchesForHeapRow(), entryIsMoveRight(), entryLocateEntry(), entryLocateLeafEntry(), ginVacuumEntryPage(), matchPartialInPendingList(), and processPendingPage().
{ Datum res; bool isnull; if (ginstate->oneCol) { /* * Single column index doesn't store attribute numbers in tuples */ res = index_getattr(tuple, FirstOffsetNumber, ginstate->origTupdesc, &isnull); } else { /* * Since the datum type depends on which index column it's from, we * must be careful to use the right tuple descriptor here. */ OffsetNumber colN = gintuple_get_attrnum(ginstate, tuple); res = index_getattr(tuple, OffsetNumberNext(FirstOffsetNumber), ginstate->tupdesc[colN - 1], &isnull); } if (isnull) *category = GinGetNullCategory(tuple, ginstate); else *category = GIN_CAT_NORM_KEY; return res; }
Datum ginvacuumcleanup | ( | PG_FUNCTION_ARGS | ) |
Definition at line 694 of file ginvacuum.c.
References IndexVacuumInfo::analyze_only, Assert, DataPageDeleteStack::blkno, BufferGetPage, IndexVacuumInfo::estimated_count, IndexBulkDeleteResult::estimated_count, ExclusiveLock, GIN_ROOT_BLKNO, GIN_SHARE, ginInsertCleanup(), GinPageIsData, GinPageIsDeleted, GinPageIsLeaf, GinPageIsList, ginUpdateStats(), IndexVacuumInfo::index, IndexFreeSpaceMapVacuum(), initGinState(), IsAutoVacuumWorkerProcess(), LockBuffer(), LockRelationForExtension(), MAIN_FORKNUM, GinStatsData::nDataPages, GinStatsData::nEntries, GinStatsData::nEntryPages, GinStatsData::nTotalPages, NULL, IndexVacuumInfo::num_heap_tuples, IndexBulkDeleteResult::num_index_tuples, IndexBulkDeleteResult::num_pages, PageGetMaxOffsetNumber, IndexBulkDeleteResult::pages_free, palloc0(), PG_GETARG_POINTER, PG_RETURN_POINTER, RBM_NORMAL, ReadBufferExtended(), RecordFreeIndexPage(), RELATION_IS_LOCAL, RelationGetNumberOfBlocks, IndexVacuumInfo::strategy, UnlockRelationForExtension(), UnlockReleaseBuffer(), and vacuum_delay_point().
{ IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0); IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1); Relation index = info->index; bool needLock; BlockNumber npages, blkno; BlockNumber totFreePages; GinState ginstate; GinStatsData idxStat; /* * In an autovacuum analyze, we want to clean up pending insertions. * Otherwise, an ANALYZE-only call is a no-op. */ if (info->analyze_only) { if (IsAutoVacuumWorkerProcess()) { initGinState(&ginstate, index); ginInsertCleanup(&ginstate, true, stats); } PG_RETURN_POINTER(stats); } /* * Set up all-zero stats and cleanup pending inserts if ginbulkdelete * wasn't called */ if (stats == NULL) { stats = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult)); initGinState(&ginstate, index); ginInsertCleanup(&ginstate, true, stats); } memset(&idxStat, 0, sizeof(idxStat)); /* * XXX we always report the heap tuple count as the number of index * entries. This is bogus if the index is partial, but it's real hard to * tell how many distinct heap entries are referenced by a GIN index. */ stats->num_index_tuples = info->num_heap_tuples; stats->estimated_count = info->estimated_count; /* * Need lock unless it's local to this backend. */ needLock = !RELATION_IS_LOCAL(index); if (needLock) LockRelationForExtension(index, ExclusiveLock); npages = RelationGetNumberOfBlocks(index); if (needLock) UnlockRelationForExtension(index, ExclusiveLock); totFreePages = 0; for (blkno = GIN_ROOT_BLKNO; blkno < npages; blkno++) { Buffer buffer; Page page; vacuum_delay_point(); buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno, RBM_NORMAL, info->strategy); LockBuffer(buffer, GIN_SHARE); page = (Page) BufferGetPage(buffer); if (GinPageIsDeleted(page)) { Assert(blkno != GIN_ROOT_BLKNO); RecordFreeIndexPage(index, blkno); totFreePages++; } else if (GinPageIsData(page)) { idxStat.nDataPages++; } else if (!GinPageIsList(page)) { idxStat.nEntryPages++; if (GinPageIsLeaf(page)) idxStat.nEntries += PageGetMaxOffsetNumber(page); } UnlockReleaseBuffer(buffer); } /* Update the metapage with accurate page and entry counts */ idxStat.nTotalPages = npages; ginUpdateStats(info->index, &idxStat); /* Finally, vacuum the FSM */ IndexFreeSpaceMapVacuum(info->index); stats->pages_free = totFreePages; if (needLock) LockRelationForExtension(index, ExclusiveLock); stats->num_pages = RelationGetNumberOfBlocks(index); if (needLock) UnlockRelationForExtension(index, ExclusiveLock); PG_RETURN_POINTER(stats); }
Definition at line 32 of file ginutil.c.
References tupleDesc::attrs, GinState::canPartialMatch, GinState::compareFn, GinState::comparePartialFn, GinState::consistentFn, CreateTemplateTupleDesc(), CurrentMemoryContext, GinState::extractQueryFn, GinState::extractValueFn, fmgr_info_copy(), GIN_COMPARE_PARTIAL_PROC, GIN_COMPARE_PROC, GIN_CONSISTENT_PROC, GIN_EXTRACTQUERY_PROC, GIN_EXTRACTVALUE_PROC, i, GinState::index, index_getprocid(), index_getprocinfo(), INT2OID, InvalidOid, MemSet, tupleDesc::natts, NULL, OidIsValid, GinState::oneCol, GinState::origTupdesc, RelationData::rd_indcollation, RelationGetDescr, GinState::supportCollation, GinState::tupdesc, TupleDescInitEntry(), and TupleDescInitEntryCollation().
Referenced by ginbeginscan(), ginbuild(), ginbulkdelete(), gininsert(), and ginvacuumcleanup().
{ TupleDesc origTupdesc = RelationGetDescr(index); int i; MemSet(state, 0, sizeof(GinState)); state->index = index; state->oneCol = (origTupdesc->natts == 1) ? true : false; state->origTupdesc = origTupdesc; for (i = 0; i < origTupdesc->natts; i++) { if (state->oneCol) state->tupdesc[i] = state->origTupdesc; else { state->tupdesc[i] = CreateTemplateTupleDesc(2, false); TupleDescInitEntry(state->tupdesc[i], (AttrNumber) 1, NULL, INT2OID, -1, 0); TupleDescInitEntry(state->tupdesc[i], (AttrNumber) 2, NULL, origTupdesc->attrs[i]->atttypid, origTupdesc->attrs[i]->atttypmod, origTupdesc->attrs[i]->attndims); TupleDescInitEntryCollation(state->tupdesc[i], (AttrNumber) 2, origTupdesc->attrs[i]->attcollation); } fmgr_info_copy(&(state->compareFn[i]), index_getprocinfo(index, i + 1, GIN_COMPARE_PROC), CurrentMemoryContext); fmgr_info_copy(&(state->extractValueFn[i]), index_getprocinfo(index, i + 1, GIN_EXTRACTVALUE_PROC), CurrentMemoryContext); fmgr_info_copy(&(state->extractQueryFn[i]), index_getprocinfo(index, i + 1, GIN_EXTRACTQUERY_PROC), CurrentMemoryContext); fmgr_info_copy(&(state->consistentFn[i]), index_getprocinfo(index, i + 1, GIN_CONSISTENT_PROC), CurrentMemoryContext); /* * Check opclass capability to do partial match. */ if (index_getprocid(index, i + 1, GIN_COMPARE_PARTIAL_PROC) != InvalidOid) { fmgr_info_copy(&(state->comparePartialFn[i]), index_getprocinfo(index, i + 1, GIN_COMPARE_PARTIAL_PROC), CurrentMemoryContext); state->canPartialMatch[i] = true; } else { state->canPartialMatch[i] = false; } /* * If the index column has a specified collation, we should honor that * while doing comparisons. However, we may have a collatable storage * type for a noncollatable indexed data type (for instance, hstore * uses text index entries). If there's no index collation then * specify default collation in case the support functions need * collation. This is harmless if the support functions don't care * about collation, so we just do it unconditionally. (We could * alternatively call get_typcollation, but that seems like expensive * overkill --- there aren't going to be any cases where a GIN storage * type has a nondefault collation.) */ if (OidIsValid(index->rd_indcollation[i])) state->supportCollation[i] = index->rd_indcollation[i]; else state->supportCollation[i] = DEFAULT_COLLATION_OID; } }