1 /*--------------------------------------------------------------------------
3 * header file for postgres inverted index access method implementation.
5 * Copyright (c) 2006-2008, PostgreSQL Global Development Group
7 * $PostgreSQL: pgsql/src/include/access/gin.h,v 1.21 2008/06/06 22:35:22 alvherre Exp $
8 *--------------------------------------------------------------------------
15 #include "access/itup.h"
16 #include "access/relscan.h"
17 #include "access/xlog.h"
19 #include "nodes/tidbitmap.h"
20 #include "storage/block.h"
21 #include "storage/buf.h"
22 #include "storage/off.h"
23 #include "storage/relfilenode.h"
27 * amproc indexes for inverted indexes.
29 #define GIN_COMPARE_PROC 1
30 #define GIN_EXTRACTVALUE_PROC 2
31 #define GIN_EXTRACTQUERY_PROC 3
32 #define GIN_CONSISTENT_PROC 4
33 #define GIN_COMPARE_PARTIAL_PROC 5
37 * Page opaque data in a inverted index page.
39 * Note: GIN does not include a page ID word as do the other index types.
40 * This is OK because the opaque data is only 8 bytes and so can be reliably
41 * distinguished by size. Revisit this if the size ever increases.
43 typedef struct GinPageOpaqueData
45 BlockNumber rightlink; /* next page if any */
46 OffsetNumber maxoff; /* number entries on GIN_DATA page: number of
47 * heap ItemPointer on GIN_DATA|GIN_LEAF page
48 * and number of records on GIN_DATA &
50 uint16 flags; /* see bit definitions below */
53 typedef GinPageOpaqueData *GinPageOpaque;
55 #define GIN_ROOT_BLKNO (0)
57 #define GIN_DATA (1 << 0)
58 #define GIN_LEAF (1 << 1)
59 #define GIN_DELETED (1 << 2)
64 #define GinPageGetOpaque(page) ( (GinPageOpaque) PageGetSpecialPointer(page) )
66 #define GinPageIsLeaf(page) ( GinPageGetOpaque(page)->flags & GIN_LEAF )
67 #define GinPageSetLeaf(page) ( GinPageGetOpaque(page)->flags |= GIN_LEAF )
68 #define GinPageSetNonLeaf(page) ( GinPageGetOpaque(page)->flags &= ~GIN_LEAF )
69 #define GinPageIsData(page) ( GinPageGetOpaque(page)->flags & GIN_DATA )
70 #define GinPageSetData(page) ( GinPageGetOpaque(page)->flags |= GIN_DATA )
72 #define GinPageIsDeleted(page) ( GinPageGetOpaque(page)->flags & GIN_DELETED)
73 #define GinPageSetDeleted(page) ( GinPageGetOpaque(page)->flags |= GIN_DELETED)
74 #define GinPageSetNonDeleted(page) ( GinPageGetOpaque(page)->flags &= ~GIN_DELETED)
76 #define GinPageRightMost(page) ( GinPageGetOpaque(page)->rightlink == InvalidBlockNumber)
79 * Define our ItemPointerGet(BlockNumber|GetOffsetNumber)
83 #define GinItemPointerGetBlockNumber(pointer) \
84 BlockIdGetBlockNumber(&(pointer)->ip_blkid)
86 #define GinItemPointerGetOffsetNumber(pointer) \
91 BlockIdData child_blkno; /* use it instead of BlockNumber to save space
96 #define PostingItemGetBlockNumber(pointer) \
97 BlockIdGetBlockNumber(&(pointer)->child_blkno)
99 #define PostingItemSetBlockNumber(pointer, blockNumber) \
100 BlockIdSet(&((pointer)->child_blkno), (blockNumber))
103 * Support work on IndexTuple on leaf pages
105 #define GinGetNPosting(itup) GinItemPointerGetOffsetNumber(&(itup)->t_tid)
106 #define GinSetNPosting(itup,n) ItemPointerSetOffsetNumber(&(itup)->t_tid,(n))
107 #define GIN_TREE_POSTING ((OffsetNumber)0xffff)
108 #define GinIsPostingTree(itup) ( GinGetNPosting(itup)==GIN_TREE_POSTING )
109 #define GinSetPostingTree(itup, blkno) ( GinSetNPosting((itup),GIN_TREE_POSTING ), ItemPointerSetBlockNumber(&(itup)->t_tid, blkno) )
110 #define GinGetPostingTree(itup) GinItemPointerGetBlockNumber(&(itup)->t_tid)
112 #define GinGetOrigSizePosting(itup) GinItemPointerGetBlockNumber(&(itup)->t_tid)
113 #define GinSetOrigSizePosting(itup,n) ItemPointerSetBlockNumber(&(itup)->t_tid,(n))
114 #define GinGetPosting(itup) ( (ItemPointer)(( ((char*)(itup)) + SHORTALIGN(GinGetOrigSizePosting(itup)) )) )
116 #define GinMaxItemSize \
117 ((BLCKSZ - SizeOfPageHeaderData - \
118 MAXALIGN(sizeof(GinPageOpaqueData))) / 3 - sizeof(ItemIdData))
122 * Data (posting tree) pages
124 #define GinDataPageGetData(page) \
125 (PageGetContents(page)+MAXALIGN(sizeof(ItemPointerData)))
126 #define GinDataPageGetRightBound(page) ((ItemPointer)PageGetContents(page))
127 #define GinSizeOfItem(page) ( (GinPageIsLeaf(page)) ? sizeof(ItemPointerData) : sizeof(PostingItem) )
128 #define GinDataPageGetItem(page,i) ( GinDataPageGetData(page) + ((i)-1) * GinSizeOfItem(page) )
130 #define GinDataPageGetFreeSpace(page) \
131 ( BLCKSZ - SizeOfPageHeaderData - MAXALIGN(sizeof(GinPageOpaqueData)) - \
132 GinPageGetOpaque(page)->maxoff * GinSizeOfItem(page) - \
133 MAXALIGN(sizeof(ItemPointerData)))
137 #define GIN_UNLOCK BUFFER_LOCK_UNLOCK
138 #define GIN_SHARE BUFFER_LOCK_SHARE
139 #define GIN_EXCLUSIVE BUFFER_LOCK_EXCLUSIVE
141 typedef struct GinState
144 FmgrInfo extractValueFn;
145 FmgrInfo extractQueryFn;
146 FmgrInfo consistentFn;
147 FmgrInfo comparePartialFn; /* optional method */
149 bool canPartialMatch; /* can opclass perform partial
150 * match (prefix search)? */
156 #define XLOG_GIN_CREATE_INDEX 0x00
158 #define XLOG_GIN_CREATE_PTREE 0x10
160 typedef struct ginxlogCreatePostingTree
165 /* follows list of heap's ItemPointer */
166 } ginxlogCreatePostingTree;
168 #define XLOG_GIN_INSERT 0x20
170 typedef struct ginxlogInsert
174 BlockNumber updateBlkno;
182 * follows: tuples or ItemPointerData or PostingItem or list of
187 #define XLOG_GIN_SPLIT 0x30
189 typedef struct ginxlogSplit
193 BlockNumber rootBlkno;
196 OffsetNumber separator;
203 BlockNumber leftChildBlkno;
204 BlockNumber updateBlkno;
206 ItemPointerData rightbound; /* used only in posting tree */
207 /* follows: list of tuple or ItemPointerData or PostingItem */
210 #define XLOG_GIN_VACUUM_PAGE 0x40
212 typedef struct ginxlogVacuumPage
217 /* follows content of page */
220 #define XLOG_GIN_DELETE_PAGE 0x50
222 typedef struct ginxlogDeletePage
226 BlockNumber parentBlkno;
227 OffsetNumber parentOffset;
228 BlockNumber leftBlkno;
229 BlockNumber rightLink;
233 extern Datum ginoptions(PG_FUNCTION_ARGS);
234 extern void initGinState(GinState *state, Relation index);
235 extern Buffer GinNewBuffer(Relation index);
236 extern void GinInitBuffer(Buffer b, uint32 f);
237 extern void GinInitPage(Page page, uint32 f, Size pageSize);
238 extern int compareEntries(GinState *ginstate, Datum a, Datum b);
239 extern Datum *extractEntriesS(GinState *ginstate, Datum value,
240 int32 *nentries, bool *needUnique);
241 extern Datum *extractEntriesSU(GinState *ginstate, Datum value, int32 *nentries);
242 extern Page GinPageGetCopyPage(Page page);
245 extern Datum ginbuild(PG_FUNCTION_ARGS);
246 extern Datum gininsert(PG_FUNCTION_ARGS);
249 extern void gin_redo(XLogRecPtr lsn, XLogRecord *record);
250 extern void gin_desc(StringInfo buf, uint8 xl_info, char *rec);
251 extern void gin_xlog_startup(void);
252 extern void gin_xlog_cleanup(void);
253 extern bool gin_safe_restartpoint(void);
257 typedef struct GinBtreeStack
262 /* predictNumber contains prediction number of pages on current level */
263 uint32 predictNumber;
264 struct GinBtreeStack *parent;
267 typedef struct GinBtreeData *GinBtree;
269 typedef struct GinBtreeData
272 BlockNumber (*findChildPage) (GinBtree, GinBtreeStack *);
273 bool (*isMoveRight) (GinBtree, Page);
274 bool (*findItem) (GinBtree, GinBtreeStack *);
277 OffsetNumber (*findChildPtr) (GinBtree, Page, BlockNumber, OffsetNumber);
278 BlockNumber (*getLeftMostPage) (GinBtree, Page);
279 bool (*isEnoughSpace) (GinBtree, Buffer, OffsetNumber);
280 void (*placeToPage) (GinBtree, Buffer, OffsetNumber, XLogRecData **);
281 Page (*splitPage) (GinBtree, Buffer, Buffer, OffsetNumber, XLogRecData **);
282 void (*fillRoot) (GinBtree, Buffer, Buffer, Buffer);
291 BlockNumber rightblkno;
298 /* Data (posting tree) option */
299 ItemPointerData *items;
306 extern GinBtreeStack *ginPrepareFindLeafPage(GinBtree btree, BlockNumber blkno);
307 extern GinBtreeStack *ginFindLeafPage(GinBtree btree, GinBtreeStack *stack);
308 extern void freeGinBtreeStack(GinBtreeStack *stack);
309 extern void ginInsertValue(GinBtree btree, GinBtreeStack *stack);
310 extern void findParents(GinBtree btree, GinBtreeStack *stack, BlockNumber rootBlkno);
313 extern IndexTuple GinFormTuple(GinState *ginstate, Datum key, ItemPointerData *ipd, uint32 nipd);
314 extern Datum ginGetHighKey(GinState *ginstate, Page page);
315 extern void prepareEntryScan(GinBtree btree, Relation index, Datum value, GinState *ginstate);
316 extern void entryFillRoot(GinBtree btree, Buffer root, Buffer lbuf, Buffer rbuf);
317 extern IndexTuple ginPageGetLinkItup(Buffer buf);
320 extern int compareItemPointers(ItemPointer a, ItemPointer b);
323 ItemPointerData *dst,
324 ItemPointerData *a, uint32 na,
325 ItemPointerData *b, uint32 nb
328 extern void GinDataPageAddItem(Page page, void *data, OffsetNumber offset);
329 extern void PageDeletePostingItem(Page page, OffsetNumber offset);
334 GinBtreeStack *stack;
335 } GinPostingTreeScan;
337 extern GinPostingTreeScan *prepareScanPostingTree(Relation index,
338 BlockNumber rootBlkno, bool searchMode);
339 extern void insertItemPointer(GinPostingTreeScan *gdi,
340 ItemPointerData *items, uint32 nitem);
341 extern Buffer scanBeginPostingTree(GinPostingTreeScan *gdi);
342 extern void dataFillRoot(GinBtree btree, Buffer root, Buffer lbuf, Buffer rbuf);
343 extern void prepareDataScan(GinBtree btree, Relation index);
347 typedef struct GinScanEntryData *GinScanEntry;
349 typedef struct GinScanEntryData
351 /* link to the equals entry in current scan key */
355 * link to values reported to consistentFn, points to
356 * GinScanKey->entryRes[i]
360 /* entry, got from extractQueryFn */
363 /* Current page in posting tree */
366 /* current ItemPointer to heap */
367 ItemPointerData curItem;
369 /* partial match support */
371 TIDBitmap *partialMatch;
372 TBMIterateResult *partialMatchResult;
373 StrategyNumber strategy;
375 /* used for Posting list and one page in Posting tree */
376 ItemPointerData *list;
382 uint32 predictNumberResult;
385 typedef struct GinScanKeyData
387 /* Number of entries in query (got by extractQueryFn) */
390 /* array of ItemPointer result, reported to consistentFn */
393 /* array of scans per entry */
394 GinScanEntry scanEntry;
396 /* for calling consistentFn(GinScanKey->entryRes, strategy, query) */
397 StrategyNumber strategy;
400 ItemPointerData curItem;
405 typedef GinScanKeyData *GinScanKey;
407 typedef struct GinScanOpaqueData
409 MemoryContext tempCtx;
414 bool isVoidRes; /* true if ginstate.extractQueryFn guarantees
415 * that nothing will be found */
420 typedef GinScanOpaqueData *GinScanOpaque;
422 extern Datum ginbeginscan(PG_FUNCTION_ARGS);
423 extern Datum ginendscan(PG_FUNCTION_ARGS);
424 extern Datum ginrescan(PG_FUNCTION_ARGS);
425 extern Datum ginmarkpos(PG_FUNCTION_ARGS);
426 extern Datum ginrestrpos(PG_FUNCTION_ARGS);
427 extern void newScanKey(IndexScanDesc scan);
430 extern PGDLLIMPORT int GinFuzzySearchLimit;
432 #define ItemPointerSetMax(p) ItemPointerSet( (p), (BlockNumber)0xffffffff, (OffsetNumber)0xffff )
433 #define ItemPointerIsMax(p) ( ItemPointerGetBlockNumber(p) == (BlockNumber)0xffffffff && ItemPointerGetOffsetNumber(p) == (OffsetNumber)0xffff )
434 #define ItemPointerSetMin(p) ItemPointerSet( (p), (BlockNumber)0, (OffsetNumber)0)
435 #define ItemPointerIsMin(p) ( ItemPointerGetBlockNumber(p) == (BlockNumber)0 && ItemPointerGetOffsetNumber(p) == (OffsetNumber)0 )
437 extern Datum gingetbitmap(PG_FUNCTION_ARGS);
438 extern Datum gingettuple(PG_FUNCTION_ARGS);
439 extern void ginrestartentry(GinScanEntry entry);
442 extern Datum ginbulkdelete(PG_FUNCTION_ARGS);
443 extern Datum ginvacuumcleanup(PG_FUNCTION_ARGS);
446 extern Datum ginarrayextract(PG_FUNCTION_ARGS);
447 extern Datum ginqueryarrayextract(PG_FUNCTION_ARGS);
448 extern Datum ginarrayconsistent(PG_FUNCTION_ARGS);
451 typedef struct EntryAccumulator
456 ItemPointerData *list;
458 struct EntryAccumulator *left;
459 struct EntryAccumulator *right;
465 EntryAccumulator *entries;
467 EntryAccumulator **stack;
469 long allocatedMemory;
472 EntryAccumulator *entryallocator;
475 extern void ginInitBA(BuildAccumulator *accum);
476 extern void ginInsertRecordBA(BuildAccumulator *accum,
477 ItemPointer heapptr, Datum *entries, int32 nentry);
478 extern ItemPointerData *ginGetEntry(BuildAccumulator *accum, Datum *entry, uint32 *n);