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