1
/*-------------------------------------------------------------------------
4
* private declarations for GiST -- declarations related to the
5
* internal implementation of GiST, not the public API
7
* Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
8
* Portions Copyright (c) 1994, Regents of the University of California
10
* src/include/access/gist_private.h
12
*-------------------------------------------------------------------------
14
#ifndef GIST_PRIVATE_H
15
#define GIST_PRIVATE_H
17
#include "access/gist.h"
18
#include "access/itup.h"
19
#include "storage/bufmgr.h"
20
#include "utils/rbtree.h"
22
/* Buffer lock modes */
23
#define GIST_SHARE BUFFER_LOCK_SHARE
24
#define GIST_EXCLUSIVE BUFFER_LOCK_EXCLUSIVE
25
#define GIST_UNLOCK BUFFER_LOCK_UNLOCK
28
* GISTSTATE: information needed for any GiST index operation
30
* This struct retains call info for the index's opclass-specific support
31
* functions (per index column), plus the index's tuple descriptor.
33
typedef struct GISTSTATE
35
FmgrInfo consistentFn[INDEX_MAX_KEYS];
36
FmgrInfo unionFn[INDEX_MAX_KEYS];
37
FmgrInfo compressFn[INDEX_MAX_KEYS];
38
FmgrInfo decompressFn[INDEX_MAX_KEYS];
39
FmgrInfo penaltyFn[INDEX_MAX_KEYS];
40
FmgrInfo picksplitFn[INDEX_MAX_KEYS];
41
FmgrInfo equalFn[INDEX_MAX_KEYS];
42
FmgrInfo distanceFn[INDEX_MAX_KEYS];
44
/* Collations to pass to the support functions */
45
Oid supportCollation[INDEX_MAX_KEYS];
52
* During a GiST index search, we must maintain a queue of unvisited items,
53
* which can be either individual heap tuples or whole index pages. If it
54
* is an ordered search, the unvisited items should be visited in distance
55
* order. Unvisited items at the same distance should be visited in
56
* depth-first order, that is heap items first, then lower index pages, then
57
* upper index pages; this rule avoids doing extra work during a search that
58
* ends early due to LIMIT.
60
* To perform an ordered search, we use an RBTree to manage the distance-order
61
* queue. Each GISTSearchTreeItem stores all unvisited items of the same
62
* distance; they are GISTSearchItems chained together via their next fields.
64
* In a non-ordered search (no order-by operators), the RBTree degenerates
65
* to a single item, which we use as a queue of unvisited index pages only.
66
* In this case matched heap items from the current index leaf page are
67
* remembered in GISTScanOpaqueData.pageData[] and returned directly from
68
* there, instead of building a separate GISTSearchItem for each one.
71
/* Individual heap tuple to be visited */
72
typedef struct GISTSearchHeapItem
74
ItemPointerData heapPtr;
75
bool recheck; /* T if quals must be rechecked */
78
/* Unvisited item, either index page or heap tuple */
79
typedef struct GISTSearchItem
81
struct GISTSearchItem *next; /* list link */
82
BlockNumber blkno; /* index page number, or InvalidBlockNumber */
85
GistNSN parentlsn; /* parent page's LSN, if index page */
86
/* we must store parentlsn to detect whether a split occurred */
87
GISTSearchHeapItem heap; /* heap info, if heap tuple */
91
#define GISTSearchItemIsHeap(item) ((item).blkno == InvalidBlockNumber)
94
* Within a GISTSearchTreeItem's chain, heap items always appear before
95
* index-page items, since we want to visit heap items first. lastHeap points
96
* to the last heap item in the chain, or is NULL if there are none.
98
typedef struct GISTSearchTreeItem
100
RBNode rbnode; /* this is an RBTree item */
101
GISTSearchItem *head; /* first chain member */
102
GISTSearchItem *lastHeap; /* last heap-tuple member, if any */
103
double distances[1]; /* array with numberOfOrderBys entries */
104
} GISTSearchTreeItem;
106
#define GSTIHDRSZ offsetof(GISTSearchTreeItem, distances)
109
* GISTScanOpaqueData: private state for a scan of a GiST index
111
typedef struct GISTScanOpaqueData
113
GISTSTATE *giststate; /* index information, see above */
114
RBTree *queue; /* queue of unvisited items */
115
MemoryContext queueCxt; /* context holding the queue */
116
MemoryContext tempCxt; /* workspace context for calling functions */
117
bool qual_ok; /* false if qual can never be satisfied */
118
bool firstCall; /* true until first gistgettuple call */
120
GISTSearchTreeItem *curTreeItem; /* current queue item, if any */
122
/* pre-allocated workspace arrays */
123
GISTSearchTreeItem *tmpTreeItem; /* workspace to pass to rb_insert */
124
double *distances; /* output area for gistindex_keytest */
126
/* In a non-ordered search, returnable heap items are stored here: */
127
GISTSearchHeapItem pageData[BLCKSZ / sizeof(IndexTupleData)];
128
OffsetNumber nPageData; /* number of valid items in array */
129
OffsetNumber curPageData; /* next item to return */
130
} GISTScanOpaqueData;
132
typedef GISTScanOpaqueData *GISTScanOpaque;
137
#define XLOG_GIST_PAGE_UPDATE 0x00
138
/* #define XLOG_GIST_NEW_ROOT 0x20 */ /* not used anymore */
139
#define XLOG_GIST_PAGE_SPLIT 0x30
140
/* #define XLOG_GIST_INSERT_COMPLETE 0x40 */ /* not used anymore */
141
#define XLOG_GIST_CREATE_INDEX 0x50
142
#define XLOG_GIST_PAGE_DELETE 0x60
144
typedef struct gistxlogPageUpdate
150
* If this operation completes a page split, by inserting a downlink for
151
* the split page, leftchild points to the left half of the split.
153
BlockNumber leftchild;
155
/* number of deleted offsets */
159
* follow: 1. todelete OffsetNumbers 2. tuples to insert
161
} gistxlogPageUpdate;
163
typedef struct gistxlogPageSplit
166
BlockNumber origblkno; /* splitted page */
167
BlockNumber origrlink; /* rightlink of the page before split */
168
GistNSN orignsn; /* NSN of the page before split */
169
bool origleaf; /* was splitted page a leaf page? */
171
BlockNumber leftchild; /* like in gistxlogPageUpdate */
172
uint16 npage; /* # of pages in the split */
175
* follow: 1. gistxlogPage and array of IndexTupleData per page
179
typedef struct gistxlogPage
182
int num; /* number of index tuples following */
185
typedef struct gistxlogPageDelete
189
} gistxlogPageDelete;
191
/* SplitedPageLayout - gistSplit function result */
192
typedef struct SplitedPageLayout
195
IndexTupleData *list;
197
IndexTuple itup; /* union key for page */
198
Page page; /* to operate */
199
Buffer buffer; /* to write after all proceed */
201
struct SplitedPageLayout *next;
205
* GISTInsertStack used for locking buffers and transfer arguments during
208
typedef struct GISTInsertStack
216
* log sequence number from page->lsn to recognize page update and compare
217
* it with page's nsn to recognize page split
222
OffsetNumber childoffnum;
224
/* pointer to parent */
225
struct GISTInsertStack *parent;
227
/* for gistFindPath */
228
struct GISTInsertStack *next;
231
typedef struct GistSplitVector
233
GIST_SPLITVEC splitVector; /* to/from PickSplit method */
235
Datum spl_lattr[INDEX_MAX_KEYS]; /* Union of subkeys in
237
bool spl_lisnull[INDEX_MAX_KEYS];
239
Datum spl_rattr[INDEX_MAX_KEYS]; /* Union of subkeys in
241
bool spl_risnull[INDEX_MAX_KEYS];
243
bool *spl_equiv; /* equivalent tuples which can be freely
244
* distributed between left and right pages */
250
Size freespace; /* free space to be left */
252
GISTInsertStack *stack;
255
/* root page of a gist index */
256
#define GIST_ROOT_BLKNO 0
259
* Before PostgreSQL 9.1, we used rely on so-called "invalid tuples" on inner
260
* pages to finish crash recovery of incomplete page splits. If a crash
261
* happened in the middle of a page split, so that the downlink pointers were
262
* not yet inserted, crash recovery inserted a special downlink pointer. The
263
* semantics of an invalid tuple was that it if you encounter one in a scan,
264
* it must always be followed, because we don't know if the tuples on the
265
* child page match or not.
267
* We no longer create such invalid tuples, we now mark the left-half of such
268
* an incomplete split with the F_FOLLOW_RIGHT flag instead, and finish the
269
* split properly the next time we need to insert on that page. To retain
270
* on-disk compatibility for the sake of pg_upgrade, we still store 0xffff as
271
* the offset number of all inner tuples. If we encounter any invalid tuples
272
* with 0xfffe during insertion, we throw an error, though scans still handle
273
* them. You should only encounter invalid tuples if you pg_upgrade a pre-9.1
274
* gist index which already has invalid tuples in it because of a crash. That
275
* should be rare, and you are recommended to REINDEX anyway if you have any
276
* invalid tuples in an index, so throwing an error is as far as we go with
279
#define TUPLE_IS_VALID 0xffff
280
#define TUPLE_IS_INVALID 0xfffe
282
#define GistTupleIsInvalid(itup) ( ItemPointerGetOffsetNumber( &((itup)->t_tid) ) == TUPLE_IS_INVALID )
283
#define GistTupleSetValid(itup) ItemPointerSetOffsetNumber( &((itup)->t_tid), TUPLE_IS_VALID )
286
extern Datum gistbuild(PG_FUNCTION_ARGS);
287
extern Datum gistbuildempty(PG_FUNCTION_ARGS);
288
extern Datum gistinsert(PG_FUNCTION_ARGS);
289
extern MemoryContext createTempGistContext(void);
290
extern void initGISTstate(GISTSTATE *giststate, Relation index);
291
extern void freeGISTstate(GISTSTATE *giststate);
293
extern SplitedPageLayout *gistSplit(Relation r, Page page, IndexTuple *itup,
294
int len, GISTSTATE *giststate);
296
extern GISTInsertStack *gistFindPath(Relation r, BlockNumber child);
299
extern void gist_redo(XLogRecPtr lsn, XLogRecord *record);
300
extern void gist_desc(StringInfo buf, uint8 xl_info, char *rec);
301
extern void gist_xlog_startup(void);
302
extern void gist_xlog_cleanup(void);
304
extern XLogRecPtr gistXLogUpdate(RelFileNode node, Buffer buffer,
305
OffsetNumber *todelete, int ntodelete,
306
IndexTuple *itup, int ntup,
309
extern XLogRecPtr gistXLogSplit(RelFileNode node,
310
BlockNumber blkno, bool page_is_leaf,
311
SplitedPageLayout *dist,
312
BlockNumber origrlink, GistNSN oldnsn,
316
extern Datum gistgettuple(PG_FUNCTION_ARGS);
317
extern Datum gistgetbitmap(PG_FUNCTION_ARGS);
321
#define GiSTPageSize \
322
( BLCKSZ - SizeOfPageHeaderData - MAXALIGN(sizeof(GISTPageOpaqueData)) )
324
#define GIST_MIN_FILLFACTOR 10
325
#define GIST_DEFAULT_FILLFACTOR 90
327
extern Datum gistoptions(PG_FUNCTION_ARGS);
328
extern bool gistfitpage(IndexTuple *itvec, int len);
329
extern bool gistnospace(Page page, IndexTuple *itvec, int len, OffsetNumber todelete, Size freespace);
330
extern void gistcheckpage(Relation rel, Buffer buf);
331
extern Buffer gistNewBuffer(Relation r);
332
extern void gistfillbuffer(Page page, IndexTuple *itup, int len,
334
extern IndexTuple *gistextractpage(Page page, int *len /* out */ );
335
extern IndexTuple *gistjoinvector(
336
IndexTuple *itvec, int *len,
337
IndexTuple *additvec, int addlen);
338
extern IndexTupleData *gistfillitupvec(IndexTuple *vec, int veclen, int *memlen);
340
extern IndexTuple gistunion(Relation r, IndexTuple *itvec,
341
int len, GISTSTATE *giststate);
342
extern IndexTuple gistgetadjusted(Relation r,
345
GISTSTATE *giststate);
346
extern IndexTuple gistFormTuple(GISTSTATE *giststate,
347
Relation r, Datum *attdata, bool *isnull, bool newValues);
349
extern OffsetNumber gistchoose(Relation r, Page p,
351
GISTSTATE *giststate);
352
extern void gistcentryinit(GISTSTATE *giststate, int nkey,
353
GISTENTRY *e, Datum k,
355
OffsetNumber o, bool l, bool isNull);
357
extern void GISTInitBuffer(Buffer b, uint32 f);
358
extern void gistdentryinit(GISTSTATE *giststate, int nkey, GISTENTRY *e,
359
Datum k, Relation r, Page pg, OffsetNumber o,
360
bool l, bool isNull);
362
extern float gistpenalty(GISTSTATE *giststate, int attno,
363
GISTENTRY *key1, bool isNull1,
364
GISTENTRY *key2, bool isNull2);
365
extern void gistMakeUnionItVec(GISTSTATE *giststate, IndexTuple *itvec, int len, int startkey,
366
Datum *attr, bool *isnull);
367
extern bool gistKeyIsEQ(GISTSTATE *giststate, int attno, Datum a, Datum b);
368
extern void gistDeCompressAtt(GISTSTATE *giststate, Relation r, IndexTuple tuple, Page p,
369
OffsetNumber o, GISTENTRY *attdata, bool *isnull);
371
extern void gistMakeUnionKey(GISTSTATE *giststate, int attno,
372
GISTENTRY *entry1, bool isnull1,
373
GISTENTRY *entry2, bool isnull2,
374
Datum *dst, bool *dstisnull);
376
extern XLogRecPtr GetXLogRecPtrForTemp(void);
379
extern Datum gistbulkdelete(PG_FUNCTION_ARGS);
380
extern Datum gistvacuumcleanup(PG_FUNCTION_ARGS);
383
extern void gistSplitByKey(Relation r, Page page, IndexTuple *itup,
384
int len, GISTSTATE *giststate,
385
GistSplitVector *v, GistEntryVector *entryvec,
388
#endif /* GIST_PRIVATE_H */