aboutsummaryrefslogtreecommitdiff
path: root/src/include/access/gin.h
blob: c13d726aa917979007ab66e9a9dc900202f84407 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
/*--------------------------------------------------------------------------
 * gin.h
 *    header file for postgres inverted index access method implementation.
 *
 *  Copyright (c) 2006, PostgreSQL Global Development Group
 *  $PostgreSQL: pgsql/src/include/access/gin.h,v 1.4 2006/07/11 13:54:24 momjian Exp $
 *--------------------------------------------------------------------------
 */


#ifndef GIN_H
#define GIN_H

#include "access/relscan.h"
#include "access/skey.h"
#include "access/xlog.h"
#include "access/xlogdefs.h"
#include "storage/bufpage.h"
#include "storage/off.h"
#include "utils/rel.h"
#include "access/itup.h"
#include "fmgr.h"


/*
 * amproc indexes for inverted indexes.
 */
#define GIN_COMPARE_PROC               1
#define GIN_EXTRACTVALUE_PROC          2
#define GIN_EXTRACTQUERY_PROC          3
#define GIN_CONSISTENT_PROC            4
#define GINNProcs                      4

typedef XLogRecPtr GinNSN;

/*
 * Page opaque data in a inverted index page.
 */
typedef struct GinPageOpaqueData {
	uint16 			flags;
 	OffsetNumber	maxoff; 	/* number entries on GIN_DATA page:
							   number of heap ItemPointer on GIN_DATA|GIN_LEAF page
							   and number of records on GIN_DATA & ~GIN_LEAF page
							 */
	BlockNumber rightlink;  
} GinPageOpaqueData;

typedef GinPageOpaqueData *GinPageOpaque;

#define GIN_ROOT_BLKNO	(0)

typedef struct {
	BlockIdData	child_blkno; /* use it instead of BlockNumber to
								save space on page */
	ItemPointerData	key;
} PostingItem;

#define	PostingItemGetBlockNumber(pointer) \
	BlockIdGetBlockNumber(&(pointer)->child_blkno)

#define	PostingItemSetBlockNumber(pointer, blockNumber) \
	BlockIdSet(&((pointer)->child_blkno), (blockNumber))

/*
 * Page opaque data in a inverted index page.
 */
#define GIN_DATA          (1 << 0)
#define GIN_LEAF          (1 << 1)
#define GIN_DELETED       (1 << 2)

/*
 * Works on page 
 */
#define GinPageGetOpaque(page) ( (GinPageOpaque) PageGetSpecialPointer(page) )

#define GinPageIsLeaf(page)    ( GinPageGetOpaque(page)->flags & GIN_LEAF )
#define GinPageSetLeaf(page)   ( GinPageGetOpaque(page)->flags |= GIN_LEAF )
#define GinPageSetNonLeaf(page)    ( GinPageGetOpaque(page)->flags &= ~GIN_LEAF )
#define GinPageIsData(page)    ( GinPageGetOpaque(page)->flags & GIN_DATA )
#define GinPageSetData(page)   ( GinPageGetOpaque(page)->flags |= GIN_DATA )

#define GinPageIsDeleted(page) ( GinPageGetOpaque(page)->flags & GIN_DELETED)
#define GinPageSetDeleted(page)    ( GinPageGetOpaque(page)->flags |= GIN_DELETED)
#define GinPageSetNonDeleted(page) ( GinPageGetOpaque(page)->flags &= ~GIN_DELETED)

#define GinPageRightMost(page) ( GinPageGetOpaque(page)->rightlink == InvalidBlockNumber)

/*
 * Define our ItemPointerGet(BlockNumber|GetOffsetNumber)
 * to prevent asserts
 */

#define GinItemPointerGetBlockNumber(pointer) \
	BlockIdGetBlockNumber(&(pointer)->ip_blkid)

#define GinItemPointerGetOffsetNumber(pointer) \
	((pointer)->ip_posid)

/*
 * Support work on IndexTuuple on leaf pages
 */
#define GinGetNPosting(itup)	GinItemPointerGetOffsetNumber(&(itup)->t_tid)
#define GinSetNPosting(itup,n)	ItemPointerSetOffsetNumber(&(itup)->t_tid,(n))
#define GIN_TREE_POSTING		((OffsetNumber)0xffff)
#define GinIsPostingTree(itup)	( GinGetNPosting(itup)==GIN_TREE_POSTING )
#define GinSetPostingTree(itup, blkno)	( GinSetNPosting((itup),GIN_TREE_POSTING ), ItemPointerSetBlockNumber(&(itup)->t_tid, blkno) ) 
#define GinGetPostingTree(itup)	GinItemPointerGetBlockNumber(&(itup)->t_tid) 

#define GinGetOrigSizePosting(itup)	GinItemPointerGetBlockNumber(&(itup)->t_tid)
#define GinSetOrigSizePosting(itup,n)	ItemPointerSetBlockNumber(&(itup)->t_tid,(n))
#define GinGetPosting(itup)			( (ItemPointer)(( ((char*)(itup)) + SHORTALIGN(GinGetOrigSizePosting(itup)) )) )

#define GinMaxItemSize \
    ((BLCKSZ - SizeOfPageHeaderData - \
		MAXALIGN(sizeof(GinPageOpaqueData))) / 3 - sizeof(ItemIdData))


/*
 * Data (posting tree) pages
 */
#define GinDataPageGetData(page)	\
	(PageGetContents(page)+MAXALIGN(sizeof(ItemPointerData)))
#define GinDataPageGetRightBound(page)	((ItemPointer)PageGetContents(page))
#define GinSizeOfItem(page)	( (GinPageIsLeaf(page)) ? sizeof(ItemPointerData) : sizeof(PostingItem) )
#define GinDataPageGetItem(page,i) ( GinDataPageGetData(page) + ((i)-1) * GinSizeOfItem(page) ) 

#define GinDataPageGetFreeSpace(page)	\
	( BLCKSZ - SizeOfPageHeaderData - MAXALIGN(sizeof(GinPageOpaqueData)) - \
		GinPageGetOpaque(page)->maxoff * GinSizeOfItem(page) - \
		MAXALIGN(sizeof(ItemPointerData)))



#define GIN_UNLOCK 	BUFFER_LOCK_UNLOCK
#define GIN_SHARE  	BUFFER_LOCK_SHARE
#define GIN_EXCLUSIVE  BUFFER_LOCK_EXCLUSIVE

typedef struct GinState {
	FmgrInfo	compareFn;
	FmgrInfo	extractValueFn;
	FmgrInfo	extractQueryFn;
	FmgrInfo	consistentFn;

	TupleDesc	tupdesc;
} GinState;

/* XLog stuff */

#define XLOG_GIN_CREATE_INDEX  0x00

#define XLOG_GIN_CREATE_PTREE  0x10

typedef struct ginxlogCreatePostingTree {
    RelFileNode 	node;
	BlockNumber 	blkno;
	uint32			nitem;
	/* follows list of heap's ItemPointer */
} ginxlogCreatePostingTree;

#define XLOG_GIN_INSERT  0x20

typedef struct ginxlogInsert {
	RelFileNode		node;
	BlockNumber		blkno;
	BlockNumber		updateBlkno;
	OffsetNumber	offset;
	bool 			isDelete;
	bool			isData;
	bool			isLeaf;
	OffsetNumber	nitem;	

	/* follows: tuples or ItemPointerData or PostingItem or list of ItemPointerData*/
} ginxlogInsert;

#define XLOG_GIN_SPLIT  0x30

typedef struct ginxlogSplit {
	RelFileNode		node;
	BlockNumber		lblkno;
	BlockNumber		rootBlkno;
	BlockNumber		rblkno;
	BlockNumber		rrlink;
	OffsetNumber	separator;
	OffsetNumber	nitem;

	bool			isData;
	bool			isLeaf;
	bool			isRootSplit;

	BlockNumber		leftChildBlkno;
	BlockNumber		updateBlkno;

	ItemPointerData	rightbound; /* used only in posting tree */
	/* follows: list of tuple or ItemPointerData or PostingItem */
} ginxlogSplit;

#define	XLOG_GIN_VACUUM_PAGE	0x40

typedef struct ginxlogVacuumPage {
	RelFileNode     node;
	BlockNumber		blkno;
	OffsetNumber	nitem;
	/* follows content of page */
} ginxlogVacuumPage;

#define XLOG_GIN_DELETE_PAGE	0x50 

typedef struct ginxlogDeletePage {
	RelFileNode		node;
	BlockNumber		blkno;
	BlockNumber		parentBlkno;
	OffsetNumber	parentOffset;
	BlockNumber		leftBlkno;
	BlockNumber		rightLink;
} ginxlogDeletePage;

/* ginutil.c */
extern Datum ginoptions(PG_FUNCTION_ARGS);
extern void initGinState( GinState *state, Relation index );
extern Buffer GinNewBuffer(Relation index);
extern void GinInitBuffer(Buffer b, uint32 f);
extern void GinInitPage(Page page, uint32 f, Size pageSize);
extern int compareEntries(GinState *ginstate, Datum a, Datum b); 
extern Datum* extractEntriesS(GinState *ginstate, Datum value, uint32 *nentries);
extern Datum* extractEntriesSU(GinState *ginstate, Datum value, uint32 *nentries);
extern Page GinPageGetCopyPage( Page page );

/* gininsert.c */
extern Datum ginbuild(PG_FUNCTION_ARGS);
extern Datum gininsert(PG_FUNCTION_ARGS);

/* ginxlog.c */
extern void gin_redo(XLogRecPtr lsn, XLogRecord *record);
extern void gin_desc(StringInfo buf, uint8 xl_info, char *rec);
extern void gin_xlog_startup(void);
extern void gin_xlog_cleanup(void);

/* ginbtree.c */

typedef struct GinBtreeStack {
	BlockNumber			blkno;
	Buffer				buffer;
	OffsetNumber 		off;
	/* predictNumber contains prediction number of pages on current level */ 
	uint32				predictNumber;
	struct GinBtreeStack *parent;
} GinBtreeStack;

typedef struct GinBtreeData *GinBtree;

typedef struct GinBtreeData {
	/* search methods */
	BlockNumber		(*findChildPage)(GinBtree, GinBtreeStack *);
	bool			(*isMoveRight)(GinBtree, Page);
	bool			(*findItem)(GinBtree, GinBtreeStack *);

	/* insert methods */
	OffsetNumber	(*findChildPtr)(GinBtree, Page, BlockNumber, OffsetNumber);
	BlockNumber		(*getLeftMostPage)(GinBtree, Page);
	bool			(*isEnoughSpace)(GinBtree, Buffer, OffsetNumber);
	void			(*placeToPage)(GinBtree, Buffer, OffsetNumber, XLogRecData**);
	Page			(*splitPage)(GinBtree, Buffer, Buffer, OffsetNumber, XLogRecData**);
	void			(*fillRoot)(GinBtree, Buffer, Buffer, Buffer);

	bool			searchMode;

	Relation		index;
	GinState		*ginstate;
	bool			fullScan;
	bool			isBuild;

	BlockNumber		rightblkno;

	/* Entry options */
	Datum			entryValue;
	IndexTuple		entry;
	bool			isDelete;

	/* Data (posting tree) option */
	ItemPointerData	*items;
	uint32			nitem;
	uint32			curitem;

	PostingItem		pitem;
} GinBtreeData;

extern GinBtreeStack* ginPrepareFindLeafPage(GinBtree btree, BlockNumber blkno);
extern GinBtreeStack* ginFindLeafPage(GinBtree btree, GinBtreeStack *stack );
extern void freeGinBtreeStack( GinBtreeStack *stack );
extern void ginInsertValue(GinBtree btree, GinBtreeStack *stack);
extern void findParents( GinBtree btree, GinBtreeStack *stack, BlockNumber rootBlkno);

/* ginentrypage.c */
extern IndexTuple GinFormTuple(GinState *ginstate, Datum key, ItemPointerData *ipd, uint32 nipd);
extern Datum ginGetHighKey(GinState *ginstate, Page page);
extern void prepareEntryScan( GinBtree btree, Relation index, Datum value, GinState *ginstate);
extern void entryFillRoot(GinBtree btree, Buffer root, Buffer lbuf, Buffer rbuf);
extern IndexTuple ginPageGetLinkItup(Buffer buf);

/* gindatapage.c */
extern int compareItemPointers( ItemPointer a, ItemPointer b );
extern void  MergeItemPointers(
				ItemPointerData *dst, 
				ItemPointerData *a, uint32 na, 
				ItemPointerData *b, uint32 nb
			);

extern void GinDataPageAddItem( Page page, void *data, OffsetNumber offset );
extern void PageDeletePostingItem(Page page, OffsetNumber offset);

typedef struct {
	GinBtreeData	btree;
	GinBtreeStack 	*stack;
} GinPostingTreeScan;

extern GinPostingTreeScan* prepareScanPostingTree( Relation index, 
			BlockNumber rootBlkno, bool searchMode);
extern void insertItemPointer(GinPostingTreeScan *gdi, 
			ItemPointerData *items, uint32 nitem);
extern Buffer scanBeginPostingTree( GinPostingTreeScan *gdi );
extern void dataFillRoot(GinBtree btree, Buffer root, Buffer lbuf, Buffer rbuf);
extern void prepareDataScan( GinBtree btree, Relation index);
/* ginscan.c */

typedef struct GinScanEntryData *GinScanEntry;

typedef struct GinScanEntryData {
	/* link to the equals entry in current scan key */
	GinScanEntry	master; 

	/* link to values reported to consistentFn,
	   points to GinScanKey->entryRes[i]*/ 
	bool			*pval; 

	/* entry, got from extractQueryFn */ 
	Datum			entry;

	/* current ItemPointer to heap, its offset in buffer and buffer */
	ItemPointerData		curItem;
	OffsetNumber		offset;
	Buffer				buffer;

	/* in case of Posing list */
	ItemPointerData		*list;
	uint32				nlist;

	bool				isFinished;
	bool				reduceResult;
	uint32				predictNumberResult;
} GinScanEntryData;

typedef struct GinScanKeyData {
	/* Number of entries in query (got by extractQueryFn) */ 
	uint32			nentries;

	/* array of ItemPointer result, reported to consistentFn */
	bool			*entryRes;

	/* array of scans per entry */ 
	GinScanEntry	scanEntry;

	/* for calling consistentFn(GinScanKey->entryRes, strategy, query) */
	StrategyNumber	strategy;
	Datum			query;

	ItemPointerData	curItem;
	bool			firstCall;
	bool			isFinished;
} GinScanKeyData;

typedef GinScanKeyData *GinScanKey; 

typedef struct GinScanOpaqueData {
	MemoryContext	tempCtx;
	GinState 		ginstate;

	GinScanKey		keys;
	uint32			nkeys;

	GinScanKey		markPos;
} GinScanOpaqueData;

typedef GinScanOpaqueData *GinScanOpaque;

extern Datum ginbeginscan(PG_FUNCTION_ARGS);
extern Datum ginendscan(PG_FUNCTION_ARGS);
extern Datum ginrescan(PG_FUNCTION_ARGS);
extern Datum ginmarkpos(PG_FUNCTION_ARGS);
extern Datum ginrestrpos(PG_FUNCTION_ARGS);
extern void newScanKey(IndexScanDesc scan);

/* ginget.c */
extern DLLIMPORT int	GinFuzzySearchLimit;

#define ItemPointerSetMax(p)	ItemPointerSet( (p), (BlockNumber)0xffffffff, (OffsetNumber)0xffff ) 
#define ItemPointerIsMax(p)	( ItemPointerGetBlockNumber(p) == (BlockNumber)0xffffffff && ItemPointerGetOffsetNumber(p) == (OffsetNumber)0xffff ) 
#define ItemPointerSetMin(p)	ItemPointerSet( (p), (BlockNumber)0, (OffsetNumber)0) 
#define ItemPointerIsMin(p)	( ItemPointerGetBlockNumber(p) == (BlockNumber)0 && ItemPointerGetOffsetNumber(p) == (OffsetNumber)0 ) 

extern Datum gingetmulti(PG_FUNCTION_ARGS);
extern Datum gingettuple(PG_FUNCTION_ARGS);

/* ginvacuum.c */
extern Datum ginbulkdelete(PG_FUNCTION_ARGS);
extern Datum ginvacuumcleanup(PG_FUNCTION_ARGS);

/* ginarrayproc.c */
extern Datum ginarrayextract(PG_FUNCTION_ARGS);
extern Datum ginarrayconsistent(PG_FUNCTION_ARGS);

/* I'm not sure that is the best place */
extern Datum arrayoverlap(PG_FUNCTION_ARGS);
extern Datum arraycontains(PG_FUNCTION_ARGS);
extern Datum arraycontained(PG_FUNCTION_ARGS);

/* ginbulk.c */
typedef struct {
    Datum       value;
	uint32      length;
	uint32      number;
	ItemPointerData *list;
	bool		shouldSort;
} EntryAccumulator;

typedef struct {
	GinState	*ginstate;
    EntryAccumulator    *entries;
	uint32      length;
	uint32      number;
	uint32      curget;
	uint32      allocatedMemory;
} BuildAccumulator;

extern void ginInitBA(BuildAccumulator *accum);
extern void ginInsertRecordBA( BuildAccumulator *accum, 
				ItemPointer heapptr, Datum *entries, uint32 nentry );
extern ItemPointerData* ginGetEntry(BuildAccumulator *accum, Datum *entry, uint32 *n);

#endif