1 | /*------------------------------------------------------------------------- |
2 | * |
3 | * spgist_private.h |
4 | * Private declarations for SP-GiST access method. |
5 | * |
6 | * |
7 | * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group |
8 | * Portions Copyright (c) 1994, Regents of the University of California |
9 | * |
10 | * src/include/access/spgist_private.h |
11 | * |
12 | *------------------------------------------------------------------------- |
13 | */ |
14 | #ifndef SPGIST_PRIVATE_H |
15 | #define SPGIST_PRIVATE_H |
16 | |
17 | #include "access/itup.h" |
18 | #include "access/spgist.h" |
19 | #include "nodes/tidbitmap.h" |
20 | #include "storage/buf.h" |
21 | #include "utils/geo_decls.h" |
22 | #include "utils/relcache.h" |
23 | |
24 | |
25 | /* Page numbers of fixed-location pages */ |
26 | #define SPGIST_METAPAGE_BLKNO (0) /* metapage */ |
27 | #define SPGIST_ROOT_BLKNO (1) /* root for normal entries */ |
28 | #define SPGIST_NULL_BLKNO (2) /* root for null-value entries */ |
29 | #define SPGIST_LAST_FIXED_BLKNO SPGIST_NULL_BLKNO |
30 | |
31 | #define SpGistBlockIsRoot(blkno) \ |
32 | ((blkno) == SPGIST_ROOT_BLKNO || (blkno) == SPGIST_NULL_BLKNO) |
33 | #define SpGistBlockIsFixed(blkno) \ |
34 | ((BlockNumber) (blkno) <= (BlockNumber) SPGIST_LAST_FIXED_BLKNO) |
35 | |
36 | /* |
37 | * Contents of page special space on SPGiST index pages |
38 | */ |
39 | typedef struct SpGistPageOpaqueData |
40 | { |
41 | uint16 flags; /* see bit definitions below */ |
42 | uint16 nRedirection; /* number of redirection tuples on page */ |
43 | uint16 nPlaceholder; /* number of placeholder tuples on page */ |
44 | /* note there's no count of either LIVE or DEAD tuples ... */ |
45 | uint16 spgist_page_id; /* for identification of SP-GiST indexes */ |
46 | } SpGistPageOpaqueData; |
47 | |
48 | typedef SpGistPageOpaqueData *SpGistPageOpaque; |
49 | |
50 | /* Flag bits in page special space */ |
51 | #define SPGIST_META (1<<0) |
52 | #define SPGIST_DELETED (1<<1) /* never set, but keep for backwards |
53 | * compatibility */ |
54 | #define SPGIST_LEAF (1<<2) |
55 | #define SPGIST_NULLS (1<<3) |
56 | |
57 | #define SpGistPageGetOpaque(page) ((SpGistPageOpaque) PageGetSpecialPointer(page)) |
58 | #define SpGistPageIsMeta(page) (SpGistPageGetOpaque(page)->flags & SPGIST_META) |
59 | #define SpGistPageIsDeleted(page) (SpGistPageGetOpaque(page)->flags & SPGIST_DELETED) |
60 | #define SpGistPageIsLeaf(page) (SpGistPageGetOpaque(page)->flags & SPGIST_LEAF) |
61 | #define SpGistPageStoresNulls(page) (SpGistPageGetOpaque(page)->flags & SPGIST_NULLS) |
62 | |
63 | /* |
64 | * The page ID is for the convenience of pg_filedump and similar utilities, |
65 | * which otherwise would have a hard time telling pages of different index |
66 | * types apart. It should be the last 2 bytes on the page. This is more or |
67 | * less "free" due to alignment considerations. |
68 | * |
69 | * See comments above GinPageOpaqueData. |
70 | */ |
71 | #define SPGIST_PAGE_ID 0xFF82 |
72 | |
73 | /* |
74 | * Each backend keeps a cache of last-used page info in its index->rd_amcache |
75 | * area. This is initialized from, and occasionally written back to, |
76 | * shared storage in the index metapage. |
77 | */ |
78 | typedef struct SpGistLastUsedPage |
79 | { |
80 | BlockNumber blkno; /* block number, or InvalidBlockNumber */ |
81 | int freeSpace; /* page's free space (could be obsolete!) */ |
82 | } SpGistLastUsedPage; |
83 | |
84 | /* Note: indexes in cachedPage[] match flag assignments for SpGistGetBuffer */ |
85 | #define SPGIST_CACHED_PAGES 8 |
86 | |
87 | typedef struct SpGistLUPCache |
88 | { |
89 | SpGistLastUsedPage cachedPage[SPGIST_CACHED_PAGES]; |
90 | } SpGistLUPCache; |
91 | |
92 | /* |
93 | * metapage |
94 | */ |
95 | typedef struct SpGistMetaPageData |
96 | { |
97 | uint32 magicNumber; /* for identity cross-check */ |
98 | SpGistLUPCache lastUsedPages; /* shared storage of last-used info */ |
99 | } SpGistMetaPageData; |
100 | |
101 | #define SPGIST_MAGIC_NUMBER (0xBA0BABEE) |
102 | |
103 | #define SpGistPageGetMeta(p) \ |
104 | ((SpGistMetaPageData *) PageGetContents(p)) |
105 | |
106 | /* |
107 | * Private state of index AM. SpGistState is common to both insert and |
108 | * search code; SpGistScanOpaque is for searches only. |
109 | */ |
110 | |
111 | /* Per-datatype info needed in SpGistState */ |
112 | typedef struct SpGistTypeDesc |
113 | { |
114 | Oid type; |
115 | bool attbyval; |
116 | int16 attlen; |
117 | } SpGistTypeDesc; |
118 | |
119 | typedef struct SpGistState |
120 | { |
121 | spgConfigOut config; /* filled in by opclass config method */ |
122 | |
123 | SpGistTypeDesc attType; /* type of values to be indexed/restored */ |
124 | SpGistTypeDesc attLeafType; /* type of leaf-tuple values */ |
125 | SpGistTypeDesc attPrefixType; /* type of inner-tuple prefix values */ |
126 | SpGistTypeDesc attLabelType; /* type of node label values */ |
127 | |
128 | char *deadTupleStorage; /* workspace for spgFormDeadTuple */ |
129 | |
130 | TransactionId myXid; /* XID to use when creating a redirect tuple */ |
131 | bool isBuild; /* true if doing index build */ |
132 | } SpGistState; |
133 | |
134 | typedef struct SpGistSearchItem |
135 | { |
136 | pairingheap_node phNode; /* pairing heap node */ |
137 | Datum value; /* value reconstructed from parent or |
138 | * leafValue if heaptuple */ |
139 | void *traversalValue; /* opclass-specific traverse value */ |
140 | int level; /* level of items on this page */ |
141 | ItemPointerData heapPtr; /* heap info, if heap tuple */ |
142 | bool isNull; /* SearchItem is NULL item */ |
143 | bool isLeaf; /* SearchItem is heap item */ |
144 | bool recheck; /* qual recheck is needed */ |
145 | bool recheckDistances; /* distance recheck is needed */ |
146 | |
147 | /* array with numberOfOrderBys entries */ |
148 | double distances[FLEXIBLE_ARRAY_MEMBER]; |
149 | } SpGistSearchItem; |
150 | |
151 | #define SizeOfSpGistSearchItem(n_distances) \ |
152 | (offsetof(SpGistSearchItem, distances) + sizeof(double) * (n_distances)) |
153 | |
154 | /* |
155 | * Private state of an index scan |
156 | */ |
157 | typedef struct SpGistScanOpaqueData |
158 | { |
159 | SpGistState state; /* see above */ |
160 | pairingheap *scanQueue; /* queue of to be visited items */ |
161 | MemoryContext tempCxt; /* short-lived memory context */ |
162 | MemoryContext traversalCxt; /* single scan lifetime memory context */ |
163 | |
164 | /* Control flags showing whether to search nulls and/or non-nulls */ |
165 | bool searchNulls; /* scan matches (all) null entries */ |
166 | bool searchNonNulls; /* scan matches (some) non-null entries */ |
167 | |
168 | /* Index quals to be passed to opclass (null-related quals removed) */ |
169 | int numberOfKeys; /* number of index qualifier conditions */ |
170 | ScanKey keyData; /* array of index qualifier descriptors */ |
171 | int numberOfOrderBys; /* number of ordering operators */ |
172 | int numberOfNonNullOrderBys; /* number of ordering operators |
173 | * with non-NULL arguments */ |
174 | ScanKey orderByData; /* array of ordering op descriptors */ |
175 | Oid *orderByTypes; /* array of ordering op return types */ |
176 | int *nonNullOrderByOffsets; /* array of offset of non-NULL |
177 | * ordering keys in the original array */ |
178 | Oid indexCollation; /* collation of index column */ |
179 | |
180 | /* Opclass defined functions: */ |
181 | FmgrInfo innerConsistentFn; |
182 | FmgrInfo leafConsistentFn; |
183 | |
184 | /* Pre-allocated workspace arrays: */ |
185 | double *zeroDistances; |
186 | double *infDistances; |
187 | |
188 | /* These fields are only used in amgetbitmap scans: */ |
189 | TIDBitmap *tbm; /* bitmap being filled */ |
190 | int64 ntids; /* number of TIDs passed to bitmap */ |
191 | |
192 | /* These fields are only used in amgettuple scans: */ |
193 | bool want_itup; /* are we reconstructing tuples? */ |
194 | TupleDesc indexTupDesc; /* if so, tuple descriptor for them */ |
195 | int nPtrs; /* number of TIDs found on current page */ |
196 | int iPtr; /* index for scanning through same */ |
197 | ItemPointerData heapPtrs[MaxIndexTuplesPerPage]; /* TIDs from cur page */ |
198 | bool recheck[MaxIndexTuplesPerPage]; /* their recheck flags */ |
199 | bool recheckDistances[MaxIndexTuplesPerPage]; /* distance recheck |
200 | * flags */ |
201 | HeapTuple reconTups[MaxIndexTuplesPerPage]; /* reconstructed tuples */ |
202 | |
203 | /* distances (for recheck) */ |
204 | IndexOrderByDistance *distances[MaxIndexTuplesPerPage]; |
205 | |
206 | /* |
207 | * Note: using MaxIndexTuplesPerPage above is a bit hokey since |
208 | * SpGistLeafTuples aren't exactly IndexTuples; however, they are larger, |
209 | * so this is safe. |
210 | */ |
211 | } SpGistScanOpaqueData; |
212 | |
213 | typedef SpGistScanOpaqueData *SpGistScanOpaque; |
214 | |
215 | /* |
216 | * This struct is what we actually keep in index->rd_amcache. It includes |
217 | * static configuration information as well as the lastUsedPages cache. |
218 | */ |
219 | typedef struct SpGistCache |
220 | { |
221 | spgConfigOut config; /* filled in by opclass config method */ |
222 | |
223 | SpGistTypeDesc attType; /* type of values to be indexed/restored */ |
224 | SpGistTypeDesc attLeafType; /* type of leaf-tuple values */ |
225 | SpGistTypeDesc attPrefixType; /* type of inner-tuple prefix values */ |
226 | SpGistTypeDesc attLabelType; /* type of node label values */ |
227 | |
228 | SpGistLUPCache lastUsedPages; /* local storage of last-used info */ |
229 | } SpGistCache; |
230 | |
231 | |
232 | /* |
233 | * SPGiST tuple types. Note: inner, leaf, and dead tuple structs |
234 | * must have the same tupstate field in the same position! Real inner and |
235 | * leaf tuples always have tupstate = LIVE; if the state is something else, |
236 | * use the SpGistDeadTuple struct to inspect the tuple. |
237 | */ |
238 | |
239 | /* values of tupstate (see README for more info) */ |
240 | #define SPGIST_LIVE 0 /* normal live tuple (either inner or leaf) */ |
241 | #define SPGIST_REDIRECT 1 /* temporary redirection placeholder */ |
242 | #define SPGIST_DEAD 2 /* dead, cannot be removed because of links */ |
243 | #define SPGIST_PLACEHOLDER 3 /* placeholder, used to preserve offsets */ |
244 | |
245 | /* |
246 | * SPGiST inner tuple: list of "nodes" that subdivide a set of tuples |
247 | * |
248 | * Inner tuple layout: |
249 | * header/optional prefix/array of nodes, which are SpGistNodeTuples |
250 | * |
251 | * size and prefixSize must be multiples of MAXALIGN |
252 | */ |
253 | typedef struct SpGistInnerTupleData |
254 | { |
255 | unsigned int tupstate:2, /* LIVE/REDIRECT/DEAD/PLACEHOLDER */ |
256 | allTheSame:1, /* all nodes in tuple are equivalent */ |
257 | nNodes:13, /* number of nodes within inner tuple */ |
258 | prefixSize:16; /* size of prefix, or 0 if none */ |
259 | uint16 size; /* total size of inner tuple */ |
260 | /* On most machines there will be a couple of wasted bytes here */ |
261 | /* prefix datum follows, then nodes */ |
262 | } SpGistInnerTupleData; |
263 | |
264 | typedef SpGistInnerTupleData *SpGistInnerTuple; |
265 | |
266 | /* these must match largest values that fit in bit fields declared above */ |
267 | #define SGITMAXNNODES 0x1FFF |
268 | #define SGITMAXPREFIXSIZE 0xFFFF |
269 | #define SGITMAXSIZE 0xFFFF |
270 | |
271 | #define SGITHDRSZ MAXALIGN(sizeof(SpGistInnerTupleData)) |
272 | #define _SGITDATA(x) (((char *) (x)) + SGITHDRSZ) |
273 | #define SGITDATAPTR(x) ((x)->prefixSize ? _SGITDATA(x) : NULL) |
274 | #define SGITDATUM(x, s) ((x)->prefixSize ? \ |
275 | ((s)->attPrefixType.attbyval ? \ |
276 | *(Datum *) _SGITDATA(x) : \ |
277 | PointerGetDatum(_SGITDATA(x))) \ |
278 | : (Datum) 0) |
279 | #define SGITNODEPTR(x) ((SpGistNodeTuple) (_SGITDATA(x) + (x)->prefixSize)) |
280 | |
281 | /* Macro for iterating through the nodes of an inner tuple */ |
282 | #define SGITITERATE(x, i, nt) \ |
283 | for ((i) = 0, (nt) = SGITNODEPTR(x); \ |
284 | (i) < (x)->nNodes; \ |
285 | (i)++, (nt) = (SpGistNodeTuple) (((char *) (nt)) + IndexTupleSize(nt))) |
286 | |
287 | /* |
288 | * SPGiST node tuple: one node within an inner tuple |
289 | * |
290 | * Node tuples use the same header as ordinary Postgres IndexTuples, but |
291 | * we do not use a null bitmap, because we know there is only one column |
292 | * so the INDEX_NULL_MASK bit suffices. Also, pass-by-value datums are |
293 | * stored as a full Datum, the same convention as for inner tuple prefixes |
294 | * and leaf tuple datums. |
295 | */ |
296 | |
297 | typedef IndexTupleData SpGistNodeTupleData; |
298 | |
299 | typedef SpGistNodeTupleData *SpGistNodeTuple; |
300 | |
301 | #define SGNTHDRSZ MAXALIGN(sizeof(SpGistNodeTupleData)) |
302 | #define SGNTDATAPTR(x) (((char *) (x)) + SGNTHDRSZ) |
303 | #define SGNTDATUM(x, s) ((s)->attLabelType.attbyval ? \ |
304 | *(Datum *) SGNTDATAPTR(x) : \ |
305 | PointerGetDatum(SGNTDATAPTR(x))) |
306 | |
307 | /* |
308 | * SPGiST leaf tuple: carries a datum and a heap tuple TID |
309 | * |
310 | * In the simplest case, the datum is the same as the indexed value; but |
311 | * it could also be a suffix or some other sort of delta that permits |
312 | * reconstruction given knowledge of the prefix path traversed to get here. |
313 | * |
314 | * The size field is wider than could possibly be needed for an on-disk leaf |
315 | * tuple, but this allows us to form leaf tuples even when the datum is too |
316 | * wide to be stored immediately, and it costs nothing because of alignment |
317 | * considerations. |
318 | * |
319 | * Normally, nextOffset links to the next tuple belonging to the same parent |
320 | * node (which must be on the same page). But when the root page is a leaf |
321 | * page, we don't chain its tuples, so nextOffset is always 0 on the root. |
322 | * |
323 | * size must be a multiple of MAXALIGN; also, it must be at least SGDTSIZE |
324 | * so that the tuple can be converted to REDIRECT status later. (This |
325 | * restriction only adds bytes for the null-datum case, otherwise alignment |
326 | * restrictions force it anyway.) |
327 | * |
328 | * In a leaf tuple for a NULL indexed value, there's no useful datum value; |
329 | * however, the SGDTSIZE limit ensures that's there's a Datum word there |
330 | * anyway, so SGLTDATUM can be applied safely as long as you don't do |
331 | * anything with the result. |
332 | */ |
333 | typedef struct SpGistLeafTupleData |
334 | { |
335 | unsigned int tupstate:2, /* LIVE/REDIRECT/DEAD/PLACEHOLDER */ |
336 | size:30; /* large enough for any palloc'able value */ |
337 | OffsetNumber nextOffset; /* next tuple in chain, or InvalidOffset */ |
338 | ItemPointerData heapPtr; /* TID of represented heap tuple */ |
339 | /* leaf datum follows */ |
340 | } SpGistLeafTupleData; |
341 | |
342 | typedef SpGistLeafTupleData *SpGistLeafTuple; |
343 | |
344 | #define SGLTHDRSZ MAXALIGN(sizeof(SpGistLeafTupleData)) |
345 | #define SGLTDATAPTR(x) (((char *) (x)) + SGLTHDRSZ) |
346 | #define SGLTDATUM(x, s) ((s)->attLeafType.attbyval ? \ |
347 | *(Datum *) SGLTDATAPTR(x) : \ |
348 | PointerGetDatum(SGLTDATAPTR(x))) |
349 | |
350 | /* |
351 | * SPGiST dead tuple: declaration for examining non-live tuples |
352 | * |
353 | * The tupstate field of this struct must match those of regular inner and |
354 | * leaf tuples, and its size field must match a leaf tuple's. |
355 | * Also, the pointer field must be in the same place as a leaf tuple's heapPtr |
356 | * field, to satisfy some Asserts that we make when replacing a leaf tuple |
357 | * with a dead tuple. |
358 | * We don't use nextOffset, but it's needed to align the pointer field. |
359 | * pointer and xid are only valid when tupstate = REDIRECT. |
360 | */ |
361 | typedef struct SpGistDeadTupleData |
362 | { |
363 | unsigned int tupstate:2, /* LIVE/REDIRECT/DEAD/PLACEHOLDER */ |
364 | size:30; |
365 | OffsetNumber nextOffset; /* not used in dead tuples */ |
366 | ItemPointerData pointer; /* redirection inside index */ |
367 | TransactionId xid; /* ID of xact that inserted this tuple */ |
368 | } SpGistDeadTupleData; |
369 | |
370 | typedef SpGistDeadTupleData *SpGistDeadTuple; |
371 | |
372 | #define SGDTSIZE MAXALIGN(sizeof(SpGistDeadTupleData)) |
373 | |
374 | /* |
375 | * Macros for doing free-space calculations. Note that when adding up the |
376 | * space needed for tuples, we always consider each tuple to need the tuple's |
377 | * size plus sizeof(ItemIdData) (for the line pointer). This works correctly |
378 | * so long as tuple sizes are always maxaligned. |
379 | */ |
380 | |
381 | /* Page capacity after allowing for fixed header and special space */ |
382 | #define SPGIST_PAGE_CAPACITY \ |
383 | MAXALIGN_DOWN(BLCKSZ - \ |
384 | SizeOfPageHeaderData - \ |
385 | MAXALIGN(sizeof(SpGistPageOpaqueData))) |
386 | |
387 | /* |
388 | * Compute free space on page, assuming that up to n placeholders can be |
389 | * recycled if present (n should be the number of tuples to be inserted) |
390 | */ |
391 | #define SpGistPageGetFreeSpace(p, n) \ |
392 | (PageGetExactFreeSpace(p) + \ |
393 | Min(SpGistPageGetOpaque(p)->nPlaceholder, n) * \ |
394 | (SGDTSIZE + sizeof(ItemIdData))) |
395 | |
396 | /* |
397 | * XLOG stuff |
398 | */ |
399 | |
400 | #define STORE_STATE(s, d) \ |
401 | do { \ |
402 | (d).myXid = (s)->myXid; \ |
403 | (d).isBuild = (s)->isBuild; \ |
404 | } while(0) |
405 | |
406 | /* |
407 | * The "flags" argument for SpGistGetBuffer should be either GBUF_LEAF to |
408 | * get a leaf page, or GBUF_INNER_PARITY(blockNumber) to get an inner |
409 | * page in the same triple-parity group as the specified block number. |
410 | * (Typically, this should be GBUF_INNER_PARITY(parentBlockNumber + 1) |
411 | * to follow the rule described in spgist/README.) |
412 | * In addition, GBUF_NULLS can be OR'd in to get a page for storage of |
413 | * null-valued tuples. |
414 | * |
415 | * Note: these flag values are used as indexes into lastUsedPages. |
416 | */ |
417 | #define GBUF_LEAF 0x03 |
418 | #define GBUF_INNER_PARITY(x) ((x) % 3) |
419 | #define GBUF_NULLS 0x04 |
420 | |
421 | #define GBUF_PARITY_MASK 0x03 |
422 | #define GBUF_REQ_LEAF(flags) (((flags) & GBUF_PARITY_MASK) == GBUF_LEAF) |
423 | #define GBUF_REQ_NULLS(flags) ((flags) & GBUF_NULLS) |
424 | |
425 | /* spgutils.c */ |
426 | extern SpGistCache *spgGetCache(Relation index); |
427 | extern void initSpGistState(SpGistState *state, Relation index); |
428 | extern Buffer SpGistNewBuffer(Relation index); |
429 | extern void SpGistUpdateMetaPage(Relation index); |
430 | extern Buffer SpGistGetBuffer(Relation index, int flags, |
431 | int needSpace, bool *isNew); |
432 | extern void SpGistSetLastUsedPage(Relation index, Buffer buffer); |
433 | extern void SpGistInitPage(Page page, uint16 f); |
434 | extern void SpGistInitBuffer(Buffer b, uint16 f); |
435 | extern void SpGistInitMetapage(Page page); |
436 | extern unsigned int SpGistGetTypeSize(SpGistTypeDesc *att, Datum datum); |
437 | extern SpGistLeafTuple spgFormLeafTuple(SpGistState *state, |
438 | ItemPointer heapPtr, |
439 | Datum datum, bool isnull); |
440 | extern SpGistNodeTuple spgFormNodeTuple(SpGistState *state, |
441 | Datum label, bool isnull); |
442 | extern SpGistInnerTuple spgFormInnerTuple(SpGistState *state, |
443 | bool hasPrefix, Datum prefix, |
444 | int nNodes, SpGistNodeTuple *nodes); |
445 | extern SpGistDeadTuple spgFormDeadTuple(SpGistState *state, int tupstate, |
446 | BlockNumber blkno, OffsetNumber offnum); |
447 | extern Datum *(SpGistState *state, |
448 | SpGistInnerTuple innerTuple); |
449 | extern OffsetNumber SpGistPageAddNewItem(SpGistState *state, Page page, |
450 | Item item, Size size, |
451 | OffsetNumber *startOffset, |
452 | bool errorOK); |
453 | extern bool spgproperty(Oid index_oid, int attno, |
454 | IndexAMProperty prop, const char *propname, |
455 | bool *res, bool *isnull); |
456 | |
457 | /* spgdoinsert.c */ |
458 | extern void spgUpdateNodeLink(SpGistInnerTuple tup, int nodeN, |
459 | BlockNumber blkno, OffsetNumber offset); |
460 | extern void spgPageIndexMultiDelete(SpGistState *state, Page page, |
461 | OffsetNumber *itemnos, int nitems, |
462 | int firststate, int reststate, |
463 | BlockNumber blkno, OffsetNumber offnum); |
464 | extern bool spgdoinsert(Relation index, SpGistState *state, |
465 | ItemPointer heapPtr, Datum datum, bool isnull); |
466 | |
467 | /* spgproc.c */ |
468 | extern double *spg_key_orderbys_distances(Datum key, bool isLeaf, |
469 | ScanKey orderbys, int norderbys); |
470 | extern BOX *box_copy(BOX *orig); |
471 | |
472 | #endif /* SPGIST_PRIVATE_H */ |
473 | |