Age Owner Branch data TLA Line data Source code
1 : : /*--------------------------------------------------------------------------
2 : : * gin_private.h
3 : : * header file for postgres inverted index access method implementation.
4 : : *
5 : : * Copyright (c) 2006-2024, PostgreSQL Global Development Group
6 : : *
7 : : * src/include/access/gin_private.h
8 : : *--------------------------------------------------------------------------
9 : : */
10 : : #ifndef GIN_PRIVATE_H
11 : : #define GIN_PRIVATE_H
12 : :
13 : : #include "access/amapi.h"
14 : : #include "access/gin.h"
15 : : #include "access/ginblock.h"
16 : : #include "access/itup.h"
17 : : #include "common/int.h"
18 : : #include "catalog/pg_am_d.h"
19 : : #include "fmgr.h"
20 : : #include "lib/rbtree.h"
21 : : #include "storage/bufmgr.h"
22 : :
23 : : /*
24 : : * Storage type for GIN's reloptions
25 : : */
26 : : typedef struct GinOptions
27 : : {
28 : : int32 vl_len_; /* varlena header (do not touch directly!) */
29 : : bool useFastUpdate; /* use fast updates? */
30 : : int pendingListCleanupSize; /* maximum size of pending list */
31 : : } GinOptions;
32 : :
33 : : #define GIN_DEFAULT_USE_FASTUPDATE true
34 : : #define GinGetUseFastUpdate(relation) \
35 : : (AssertMacro(relation->rd_rel->relkind == RELKIND_INDEX && \
36 : : relation->rd_rel->relam == GIN_AM_OID), \
37 : : (relation)->rd_options ? \
38 : : ((GinOptions *) (relation)->rd_options)->useFastUpdate : GIN_DEFAULT_USE_FASTUPDATE)
39 : : #define GinGetPendingListCleanupSize(relation) \
40 : : (AssertMacro(relation->rd_rel->relkind == RELKIND_INDEX && \
41 : : relation->rd_rel->relam == GIN_AM_OID), \
42 : : (relation)->rd_options && \
43 : : ((GinOptions *) (relation)->rd_options)->pendingListCleanupSize != -1 ? \
44 : : ((GinOptions *) (relation)->rd_options)->pendingListCleanupSize : \
45 : : gin_pending_list_limit)
46 : :
47 : :
48 : : /* Macros for buffer lock/unlock operations */
49 : : #define GIN_UNLOCK BUFFER_LOCK_UNLOCK
50 : : #define GIN_SHARE BUFFER_LOCK_SHARE
51 : : #define GIN_EXCLUSIVE BUFFER_LOCK_EXCLUSIVE
52 : :
53 : :
54 : : /*
55 : : * GinState: working data structure describing the index being worked on
56 : : */
57 : : typedef struct GinState
58 : : {
59 : : Relation index;
60 : : bool oneCol; /* true if single-column index */
61 : :
62 : : /*
63 : : * origTupdesc is the nominal tuple descriptor of the index, ie, the i'th
64 : : * attribute shows the key type (not the input data type!) of the i'th
65 : : * index column. In a single-column index this describes the actual leaf
66 : : * index tuples. In a multi-column index, the actual leaf tuples contain
67 : : * a smallint column number followed by a key datum of the appropriate
68 : : * type for that column. We set up tupdesc[i] to describe the actual
69 : : * rowtype of the index tuples for the i'th column, ie, (int2, keytype).
70 : : * Note that in any case, leaf tuples contain more data than is known to
71 : : * the TupleDesc; see access/gin/README for details.
72 : : */
73 : : TupleDesc origTupdesc;
74 : : TupleDesc tupdesc[INDEX_MAX_KEYS];
75 : :
76 : : /*
77 : : * Per-index-column opclass support functions
78 : : */
79 : : FmgrInfo compareFn[INDEX_MAX_KEYS];
80 : : FmgrInfo extractValueFn[INDEX_MAX_KEYS];
81 : : FmgrInfo extractQueryFn[INDEX_MAX_KEYS];
82 : : FmgrInfo consistentFn[INDEX_MAX_KEYS];
83 : : FmgrInfo triConsistentFn[INDEX_MAX_KEYS];
84 : : FmgrInfo comparePartialFn[INDEX_MAX_KEYS]; /* optional method */
85 : : /* canPartialMatch[i] is true if comparePartialFn[i] is valid */
86 : : bool canPartialMatch[INDEX_MAX_KEYS];
87 : : /* Collations to pass to the support functions */
88 : : Oid supportCollation[INDEX_MAX_KEYS];
89 : : } GinState;
90 : :
91 : :
92 : : /* ginutil.c */
93 : : extern bytea *ginoptions(Datum reloptions, bool validate);
94 : : extern void initGinState(GinState *state, Relation index);
95 : : extern Buffer GinNewBuffer(Relation index);
96 : : extern void GinInitBuffer(Buffer b, uint32 f);
97 : : extern void GinInitPage(Page page, uint32 f, Size pageSize);
98 : : extern void GinInitMetabuffer(Buffer b);
99 : : extern int ginCompareEntries(GinState *ginstate, OffsetNumber attnum,
100 : : Datum a, GinNullCategory categorya,
101 : : Datum b, GinNullCategory categoryb);
102 : : extern int ginCompareAttEntries(GinState *ginstate,
103 : : OffsetNumber attnuma, Datum a, GinNullCategory categorya,
104 : : OffsetNumber attnumb, Datum b, GinNullCategory categoryb);
105 : : extern Datum *ginExtractEntries(GinState *ginstate, OffsetNumber attnum,
106 : : Datum value, bool isNull,
107 : : int32 *nentries, GinNullCategory **categories);
108 : :
109 : : extern OffsetNumber gintuple_get_attrnum(GinState *ginstate, IndexTuple tuple);
110 : : extern Datum gintuple_get_key(GinState *ginstate, IndexTuple tuple,
111 : : GinNullCategory *category);
112 : :
113 : : /* gininsert.c */
114 : : extern IndexBuildResult *ginbuild(Relation heap, Relation index,
115 : : struct IndexInfo *indexInfo);
116 : : extern void ginbuildempty(Relation index);
117 : : extern bool gininsert(Relation index, Datum *values, bool *isnull,
118 : : ItemPointer ht_ctid, Relation heapRel,
119 : : IndexUniqueCheck checkUnique,
120 : : bool indexUnchanged,
121 : : struct IndexInfo *indexInfo);
122 : : extern void ginEntryInsert(GinState *ginstate,
123 : : OffsetNumber attnum, Datum key, GinNullCategory category,
124 : : ItemPointerData *items, uint32 nitem,
125 : : GinStatsData *buildStats);
126 : :
127 : : /* ginbtree.c */
128 : :
129 : : typedef struct GinBtreeStack
130 : : {
131 : : BlockNumber blkno;
132 : : Buffer buffer;
133 : : OffsetNumber off;
134 : : ItemPointerData iptr;
135 : : /* predictNumber contains predicted number of pages on current level */
136 : : uint32 predictNumber;
137 : : struct GinBtreeStack *parent;
138 : : } GinBtreeStack;
139 : :
140 : : typedef struct GinBtreeData *GinBtree;
141 : :
142 : : /* Return codes for GinBtreeData.beginPlaceToPage method */
143 : : typedef enum
144 : : {
145 : : GPTP_NO_WORK,
146 : : GPTP_INSERT,
147 : : GPTP_SPLIT,
148 : : } GinPlaceToPageRC;
149 : :
150 : : typedef struct GinBtreeData
151 : : {
152 : : /* search methods */
153 : : BlockNumber (*findChildPage) (GinBtree, GinBtreeStack *);
154 : : BlockNumber (*getLeftMostChild) (GinBtree, Page);
155 : : bool (*isMoveRight) (GinBtree, Page);
156 : : bool (*findItem) (GinBtree, GinBtreeStack *);
157 : :
158 : : /* insert methods */
159 : : OffsetNumber (*findChildPtr) (GinBtree, Page, BlockNumber, OffsetNumber);
160 : : GinPlaceToPageRC (*beginPlaceToPage) (GinBtree, Buffer, GinBtreeStack *, void *, BlockNumber, void **, Page *, Page *);
161 : : void (*execPlaceToPage) (GinBtree, Buffer, GinBtreeStack *, void *, BlockNumber, void *);
162 : : void *(*prepareDownlink) (GinBtree, Buffer);
163 : : void (*fillRoot) (GinBtree, Page, BlockNumber, Page, BlockNumber, Page);
164 : :
165 : : bool isData;
166 : :
167 : : Relation index;
168 : : BlockNumber rootBlkno;
169 : : GinState *ginstate; /* not valid in a data scan */
170 : : bool fullScan;
171 : : bool isBuild;
172 : :
173 : : /* Search key for Entry tree */
174 : : OffsetNumber entryAttnum;
175 : : Datum entryKey;
176 : : GinNullCategory entryCategory;
177 : :
178 : : /* Search key for data tree (posting tree) */
179 : : ItemPointerData itemptr;
180 : : } GinBtreeData;
181 : :
182 : : /* This represents a tuple to be inserted to entry tree. */
183 : : typedef struct
184 : : {
185 : : IndexTuple entry; /* tuple to insert */
186 : : bool isDelete; /* delete old tuple at same offset? */
187 : : } GinBtreeEntryInsertData;
188 : :
189 : : /*
190 : : * This represents an itempointer, or many itempointers, to be inserted to
191 : : * a data (posting tree) leaf page
192 : : */
193 : : typedef struct
194 : : {
195 : : ItemPointerData *items;
196 : : uint32 nitem;
197 : : uint32 curitem;
198 : : } GinBtreeDataLeafInsertData;
199 : :
200 : : /*
201 : : * For internal data (posting tree) pages, the insertion payload is a
202 : : * PostingItem
203 : : */
204 : :
205 : : extern GinBtreeStack *ginFindLeafPage(GinBtree btree, bool searchMode,
206 : : bool rootConflictCheck);
207 : : extern Buffer ginStepRight(Buffer buffer, Relation index, int lockmode);
208 : : extern void freeGinBtreeStack(GinBtreeStack *stack);
209 : : extern void ginInsertValue(GinBtree btree, GinBtreeStack *stack,
210 : : void *insertdata, GinStatsData *buildStats);
211 : :
212 : : /* ginentrypage.c */
213 : : extern IndexTuple GinFormTuple(GinState *ginstate,
214 : : OffsetNumber attnum, Datum key, GinNullCategory category,
215 : : Pointer data, Size dataSize, int nipd, bool errorTooBig);
216 : : extern void ginPrepareEntryScan(GinBtree btree, OffsetNumber attnum,
217 : : Datum key, GinNullCategory category,
218 : : GinState *ginstate);
219 : : extern void ginEntryFillRoot(GinBtree btree, Page root, BlockNumber lblkno, Page lpage, BlockNumber rblkno, Page rpage);
220 : : extern ItemPointer ginReadTuple(GinState *ginstate, OffsetNumber attnum,
221 : : IndexTuple itup, int *nitems);
222 : :
223 : : /* gindatapage.c */
224 : : extern ItemPointer GinDataLeafPageGetItems(Page page, int *nitems, ItemPointerData advancePast);
225 : : extern int GinDataLeafPageGetItemsToTbm(Page page, TIDBitmap *tbm);
226 : : extern BlockNumber createPostingTree(Relation index,
227 : : ItemPointerData *items, uint32 nitems,
228 : : GinStatsData *buildStats, Buffer entrybuffer);
229 : : extern void GinDataPageAddPostingItem(Page page, PostingItem *data, OffsetNumber offset);
230 : : extern void GinPageDeletePostingItem(Page page, OffsetNumber offset);
231 : : extern void ginInsertItemPointers(Relation index, BlockNumber rootBlkno,
232 : : ItemPointerData *items, uint32 nitem,
233 : : GinStatsData *buildStats);
234 : : extern GinBtreeStack *ginScanBeginPostingTree(GinBtree btree, Relation index, BlockNumber rootBlkno);
235 : : extern void ginDataFillRoot(GinBtree btree, Page root, BlockNumber lblkno, Page lpage, BlockNumber rblkno, Page rpage);
236 : :
237 : : /*
238 : : * This is declared in ginvacuum.c, but is passed between ginVacuumItemPointers
239 : : * and ginVacuumPostingTreeLeaf and as an opaque struct, so we need a forward
240 : : * declaration for it.
241 : : */
242 : : typedef struct GinVacuumState GinVacuumState;
243 : :
244 : : extern void ginVacuumPostingTreeLeaf(Relation indexrel, Buffer buffer,
245 : : GinVacuumState *gvs);
246 : :
247 : : /* ginscan.c */
248 : :
249 : : /*
250 : : * GinScanKeyData describes a single GIN index qualifier expression.
251 : : *
252 : : * From each qual expression, we extract one or more specific index search
253 : : * conditions, which are represented by GinScanEntryData. It's quite
254 : : * possible for identical search conditions to be requested by more than
255 : : * one qual expression, in which case we merge such conditions to have just
256 : : * one unique GinScanEntry --- this is particularly important for efficiency
257 : : * when dealing with full-index-scan entries. So there can be multiple
258 : : * GinScanKeyData.scanEntry pointers to the same GinScanEntryData.
259 : : *
260 : : * In each GinScanKeyData, nentries is the true number of entries, while
261 : : * nuserentries is the number that extractQueryFn returned (which is what
262 : : * we report to consistentFn). The "user" entries must come first.
263 : : */
264 : : typedef struct GinScanKeyData *GinScanKey;
265 : :
266 : : typedef struct GinScanEntryData *GinScanEntry;
267 : :
268 : : typedef struct GinScanKeyData
269 : : {
270 : : /* Real number of entries in scanEntry[] (always > 0) */
271 : : uint32 nentries;
272 : : /* Number of entries that extractQueryFn and consistentFn know about */
273 : : uint32 nuserentries;
274 : :
275 : : /* array of GinScanEntry pointers, one per extracted search condition */
276 : : GinScanEntry *scanEntry;
277 : :
278 : : /*
279 : : * At least one of the entries in requiredEntries must be present for a
280 : : * tuple to match the overall qual.
281 : : *
282 : : * additionalEntries contains entries that are needed by the consistent
283 : : * function to decide if an item matches, but are not sufficient to
284 : : * satisfy the qual without entries from requiredEntries.
285 : : */
286 : : GinScanEntry *requiredEntries;
287 : : int nrequired;
288 : : GinScanEntry *additionalEntries;
289 : : int nadditional;
290 : :
291 : : /* array of check flags, reported to consistentFn */
292 : : GinTernaryValue *entryRes;
293 : : bool (*boolConsistentFn) (GinScanKey key);
294 : : GinTernaryValue (*triConsistentFn) (GinScanKey key);
295 : : FmgrInfo *consistentFmgrInfo;
296 : : FmgrInfo *triConsistentFmgrInfo;
297 : : Oid collation;
298 : :
299 : : /* other data needed for calling consistentFn */
300 : : Datum query;
301 : : /* NB: these three arrays have only nuserentries elements! */
302 : : Datum *queryValues;
303 : : GinNullCategory *queryCategories;
304 : : Pointer *extra_data;
305 : : StrategyNumber strategy;
306 : : int32 searchMode;
307 : : OffsetNumber attnum;
308 : :
309 : : /*
310 : : * An excludeOnly scan key is not able to enumerate all matching tuples.
311 : : * That is, to be semantically correct on its own, it would need to have a
312 : : * GIN_CAT_EMPTY_QUERY scanEntry, but it doesn't. Such a key can still be
313 : : * used to filter tuples returned by other scan keys, so we will get the
314 : : * right answers as long as there's at least one non-excludeOnly scan key
315 : : * for each index attribute considered by the search. For efficiency
316 : : * reasons we don't want to have unnecessary GIN_CAT_EMPTY_QUERY entries,
317 : : * so we will convert an excludeOnly scan key to non-excludeOnly (by
318 : : * adding a GIN_CAT_EMPTY_QUERY scanEntry) only if there are no other
319 : : * non-excludeOnly scan keys.
320 : : */
321 : : bool excludeOnly;
322 : :
323 : : /*
324 : : * Match status data. curItem is the TID most recently tested (could be a
325 : : * lossy-page pointer). curItemMatches is true if it passes the
326 : : * consistentFn test; if so, recheckCurItem is the recheck flag.
327 : : * isFinished means that all the input entry streams are finished, so this
328 : : * key cannot succeed for any later TIDs.
329 : : */
330 : : ItemPointerData curItem;
331 : : bool curItemMatches;
332 : : bool recheckCurItem;
333 : : bool isFinished;
334 : : } GinScanKeyData;
335 : :
336 : : typedef struct GinScanEntryData
337 : : {
338 : : /* query key and other information from extractQueryFn */
339 : : Datum queryKey;
340 : : GinNullCategory queryCategory;
341 : : bool isPartialMatch;
342 : : Pointer extra_data;
343 : : StrategyNumber strategy;
344 : : int32 searchMode;
345 : : OffsetNumber attnum;
346 : :
347 : : /* Current page in posting tree */
348 : : Buffer buffer;
349 : :
350 : : /* current ItemPointer to heap */
351 : : ItemPointerData curItem;
352 : :
353 : : /* for a partial-match or full-scan query, we accumulate all TIDs here */
354 : : TIDBitmap *matchBitmap;
355 : : TBMIterator *matchIterator;
356 : : TBMIterateResult *matchResult;
357 : :
358 : : /* used for Posting list and one page in Posting tree */
359 : : ItemPointerData *list;
360 : : int nlist;
361 : : OffsetNumber offset;
362 : :
363 : : bool isFinished;
364 : : bool reduceResult;
365 : : uint32 predictNumberResult;
366 : : GinBtreeData btree;
367 : : } GinScanEntryData;
368 : :
369 : : typedef struct GinScanOpaqueData
370 : : {
371 : : MemoryContext tempCtx;
372 : : GinState ginstate;
373 : :
374 : : GinScanKey keys; /* one per scan qualifier expr */
375 : : uint32 nkeys;
376 : :
377 : : GinScanEntry *entries; /* one per index search condition */
378 : : uint32 totalentries;
379 : : uint32 allocentries; /* allocated length of entries[] */
380 : :
381 : : MemoryContext keyCtx; /* used to hold key and entry data */
382 : :
383 : : bool isVoidRes; /* true if query is unsatisfiable */
384 : : } GinScanOpaqueData;
385 : :
386 : : typedef GinScanOpaqueData *GinScanOpaque;
387 : :
388 : : extern IndexScanDesc ginbeginscan(Relation rel, int nkeys, int norderbys);
389 : : extern void ginendscan(IndexScanDesc scan);
390 : : extern void ginrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,
391 : : ScanKey orderbys, int norderbys);
392 : : extern void ginNewScanKey(IndexScanDesc scan);
393 : : extern void ginFreeScanKeys(GinScanOpaque so);
394 : :
395 : : /* ginget.c */
396 : : extern int64 gingetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
397 : :
398 : : /* ginlogic.c */
399 : : extern void ginInitConsistentFunction(GinState *ginstate, GinScanKey key);
400 : :
401 : : /* ginvacuum.c */
402 : : extern IndexBulkDeleteResult *ginbulkdelete(IndexVacuumInfo *info,
403 : : IndexBulkDeleteResult *stats,
404 : : IndexBulkDeleteCallback callback,
405 : : void *callback_state);
406 : : extern IndexBulkDeleteResult *ginvacuumcleanup(IndexVacuumInfo *info,
407 : : IndexBulkDeleteResult *stats);
408 : : extern ItemPointer ginVacuumItemPointers(GinVacuumState *gvs,
409 : : ItemPointerData *items, int nitem, int *nremaining);
410 : :
411 : : /* ginvalidate.c */
412 : : extern bool ginvalidate(Oid opclassoid);
413 : : extern void ginadjustmembers(Oid opfamilyoid,
414 : : Oid opclassoid,
415 : : List *operators,
416 : : List *functions);
417 : :
418 : : /* ginbulk.c */
419 : : typedef struct GinEntryAccumulator
420 : : {
421 : : RBTNode rbtnode;
422 : : Datum key;
423 : : GinNullCategory category;
424 : : OffsetNumber attnum;
425 : : bool shouldSort;
426 : : ItemPointerData *list;
427 : : uint32 maxcount; /* allocated size of list[] */
428 : : uint32 count; /* current number of list[] entries */
429 : : } GinEntryAccumulator;
430 : :
431 : : typedef struct
432 : : {
433 : : GinState *ginstate;
434 : : Size allocatedMemory;
435 : : GinEntryAccumulator *entryallocator;
436 : : uint32 eas_used;
437 : : RBTree *tree;
438 : : RBTreeIterator tree_walk;
439 : : } BuildAccumulator;
440 : :
441 : : extern void ginInitBA(BuildAccumulator *accum);
442 : : extern void ginInsertBAEntries(BuildAccumulator *accum,
443 : : ItemPointer heapptr, OffsetNumber attnum,
444 : : Datum *entries, GinNullCategory *categories,
445 : : int32 nentries);
446 : : extern void ginBeginBAScan(BuildAccumulator *accum);
447 : : extern ItemPointerData *ginGetBAEntry(BuildAccumulator *accum,
448 : : OffsetNumber *attnum, Datum *key, GinNullCategory *category,
449 : : uint32 *n);
450 : :
451 : : /* ginfast.c */
452 : :
453 : : typedef struct GinTupleCollector
454 : : {
455 : : IndexTuple *tuples;
456 : : uint32 ntuples;
457 : : uint32 lentuples;
458 : : uint32 sumsize;
459 : : } GinTupleCollector;
460 : :
461 : : extern void ginHeapTupleFastInsert(GinState *ginstate,
462 : : GinTupleCollector *collector);
463 : : extern void ginHeapTupleFastCollect(GinState *ginstate,
464 : : GinTupleCollector *collector,
465 : : OffsetNumber attnum, Datum value, bool isNull,
466 : : ItemPointer ht_ctid);
467 : : extern void ginInsertCleanup(GinState *ginstate, bool full_clean,
468 : : bool fill_fsm, bool forceCleanup, IndexBulkDeleteResult *stats);
469 : :
470 : : /* ginpostinglist.c */
471 : :
472 : : extern GinPostingList *ginCompressPostingList(const ItemPointer ipd, int nipd,
473 : : int maxsize, int *nwritten);
474 : : extern int ginPostingListDecodeAllSegmentsToTbm(GinPostingList *ptr, int len, TIDBitmap *tbm);
475 : :
476 : : extern ItemPointer ginPostingListDecodeAllSegments(GinPostingList *segment, int len,
477 : : int *ndecoded_out);
478 : : extern ItemPointer ginPostingListDecode(GinPostingList *plist, int *ndecoded_out);
479 : : extern ItemPointer ginMergeItemPointers(ItemPointerData *a, uint32 na,
480 : : ItemPointerData *b, uint32 nb,
481 : : int *nmerged);
482 : :
483 : : /*
484 : : * Merging the results of several gin scans compares item pointers a lot,
485 : : * so we want this to be inlined.
486 : : */
487 : : static inline int
3942 heikki.linnakangas@i 488 :CBC 6409785 : ginCompareItemPointers(ItemPointer a, ItemPointer b)
489 : : {
2574 alvherre@alvh.no-ip. 490 : 6409785 : uint64 ia = (uint64) GinItemPointerGetBlockNumber(a) << 32 | GinItemPointerGetOffsetNumber(a);
491 : 6409785 : uint64 ib = (uint64) GinItemPointerGetBlockNumber(b) << 32 | GinItemPointerGetOffsetNumber(b);
492 : :
58 nathan@postgresql.or 493 :GNC 6409785 : return pg_cmp_u64(ia, ib);
494 : : }
495 : :
496 : : extern int ginTraverseLock(Buffer buffer, bool searchMode);
497 : :
498 : : #endif /* GIN_PRIVATE_H */
|