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