PostgreSQL Source Code git master
Loading...
Searching...
No Matches
gist_private.h File Reference
#include "access/amapi.h"
#include "access/gist.h"
#include "access/itup.h"
#include "lib/pairingheap.h"
#include "storage/bufmgr.h"
#include "storage/buffile.h"
#include "utils/hsearch.h"
#include "access/genam.h"
Include dependency graph for gist_private.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  GISTNodeBufferPage
 
struct  GISTSTATE
 
struct  GISTSearchHeapItem
 
struct  GISTSearchItem
 
struct  GISTScanOpaqueData
 
struct  gistxlogPage
 
struct  SplitPageLayout
 
struct  GISTInsertStack
 
struct  GistSplitVector
 
struct  GISTInsertState
 
struct  GISTNodeBuffer
 
struct  GISTBuildBuffers
 
struct  GiSTOptions
 
struct  GISTPageSplitInfo
 

Macros

#define GIST_MAX_SPLIT_PAGES   75
 
#define GIST_SHARE   BUFFER_LOCK_SHARE
 
#define GIST_EXCLUSIVE   BUFFER_LOCK_EXCLUSIVE
 
#define GIST_UNLOCK   BUFFER_LOCK_UNLOCK
 
#define BUFFER_PAGE_DATA_OFFSET   MAXALIGN(offsetof(GISTNodeBufferPage, tupledata))
 
#define PAGE_FREE_SPACE(nbp)   (nbp->freespace)
 
#define PAGE_IS_EMPTY(nbp)   (nbp->freespace == BLCKSZ - BUFFER_PAGE_DATA_OFFSET)
 
#define PAGE_NO_SPACE(nbp, itup)
 
#define GISTSearchItemIsHeap(item)   ((item).blkno == InvalidBlockNumber)
 
#define SizeOfGISTSearchItem(n_distances)
 
#define GIST_ROOT_BLKNO   0
 
#define TUPLE_IS_VALID   0xffff
 
#define TUPLE_IS_INVALID   0xfffe
 
#define GistTupleIsInvalid(itup)   ( ItemPointerGetOffsetNumber( &((itup)->t_tid) ) == TUPLE_IS_INVALID )
 
#define GistTupleSetValid(itup)   ItemPointerSetOffsetNumber( &((itup)->t_tid), TUPLE_IS_VALID )
 
#define LEVEL_HAS_BUFFERS(nlevel, gfbb)
 
#define BUFFER_HALF_FILLED(nodeBuffer, gfbb)    ((nodeBuffer)->blocksCount > (gfbb)->pagesPerBuffer / 2)
 
#define BUFFER_OVERFLOWED(nodeBuffer, gfbb)    ((nodeBuffer)->blocksCount > (gfbb)->pagesPerBuffer)
 
#define GiSTPageSize    ( BLCKSZ - SizeOfPageHeaderData - MAXALIGN(sizeof(GISTPageOpaqueData)) )
 
#define GIST_MIN_FILLFACTOR   10
 
#define GIST_DEFAULT_FILLFACTOR   90
 

Typedefs

typedef struct GISTSTATE GISTSTATE
 
typedef struct GISTSearchHeapItem GISTSearchHeapItem
 
typedef struct GISTSearchItem GISTSearchItem
 
typedef struct GISTScanOpaqueData GISTScanOpaqueData
 
typedef GISTScanOpaqueDataGISTScanOpaque
 
typedef struct gistxlogPage gistxlogPage
 
typedef struct SplitPageLayout SplitPageLayout
 
typedef struct GISTInsertStack GISTInsertStack
 
typedef struct GistSplitVector GistSplitVector
 
typedef struct GISTBuildBuffers GISTBuildBuffers
 
typedef enum GistOptBufferingMode GistOptBufferingMode
 
typedef struct GiSTOptions GiSTOptions
 

Enumerations

enum  GistOptBufferingMode { GIST_OPTION_BUFFERING_AUTO , GIST_OPTION_BUFFERING_ON , GIST_OPTION_BUFFERING_OFF }
 

Functions

void gistbuildempty (Relation index)
 
bool gistinsert (Relation r, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, IndexUniqueCheck checkUnique, bool indexUnchanged, struct IndexInfo *indexInfo)
 
MemoryContext createTempGistContext (void)
 
GISTSTATEinitGISTstate (Relation index)
 
void freeGISTstate (GISTSTATE *giststate)
 
void gistdoinsert (Relation r, IndexTuple itup, Size freespace, GISTSTATE *giststate, Relation heapRel, bool is_build)
 
bool gistplacetopage (Relation rel, Size freespace, GISTSTATE *giststate, Buffer buffer, IndexTuple *itup, int ntup, OffsetNumber oldoffnum, BlockNumber *newblkno, Buffer leftchildbuf, List **splitinfo, bool markfollowright, Relation heapRel, bool is_build)
 
SplitPageLayoutgistSplit (Relation r, Page page, IndexTuple *itup, int len, GISTSTATE *giststate)
 
XLogRecPtr gistXLogPageDelete (Buffer buffer, FullTransactionId xid, Buffer parentBuffer, OffsetNumber downlinkOffset)
 
void gistXLogPageReuse (Relation rel, Relation heaprel, BlockNumber blkno, FullTransactionId deleteXid)
 
XLogRecPtr gistXLogUpdate (Buffer buffer, OffsetNumber *todelete, int ntodelete, IndexTuple *itup, int ituplen, Buffer leftchildbuf)
 
XLogRecPtr gistXLogDelete (Buffer buffer, OffsetNumber *todelete, int ntodelete, TransactionId snapshotConflictHorizon, Relation heaprel)
 
XLogRecPtr gistXLogSplit (bool page_is_leaf, SplitPageLayout *dist, BlockNumber origrlink, GistNSN orignsn, Buffer leftchildbuf, bool markfollowright)
 
XLogRecPtr gistXLogAssignLSN (void)
 
bool gistgettuple (IndexScanDesc scan, ScanDirection dir)
 
int64 gistgetbitmap (IndexScanDesc scan, TIDBitmap *tbm)
 
bool gistcanreturn (Relation index, int attno)
 
bool gistvalidate (Oid opclassoid)
 
void gistadjustmembers (Oid opfamilyoid, Oid opclassoid, List *operators, List *functions)
 
byteagistoptions (Datum reloptions, bool validate)
 
bool gistproperty (Oid index_oid, int attno, IndexAMProperty prop, const char *propname, bool *res, bool *isnull)
 
bool gistfitpage (IndexTuple *itvec, int len)
 
bool gistnospace (Page page, IndexTuple *itvec, int len, OffsetNumber todelete, Size freespace)
 
void gistcheckpage (Relation rel, Buffer buf)
 
Buffer gistNewBuffer (Relation r, Relation heaprel)
 
bool gistPageRecyclable (Page page)
 
void gistfillbuffer (Page page, IndexTuple *itup, int len, OffsetNumber off)
 
IndexTuplegistextractpage (Page page, int *len)
 
IndexTuplegistjoinvector (IndexTuple *itvec, int *len, IndexTuple *additvec, int addlen)
 
IndexTupleDatagistfillitupvec (IndexTuple *vec, int veclen, int *memlen)
 
IndexTuple gistunion (Relation r, IndexTuple *itvec, int len, GISTSTATE *giststate)
 
IndexTuple gistgetadjusted (Relation r, IndexTuple oldtup, IndexTuple addtup, GISTSTATE *giststate)
 
IndexTuple gistFormTuple (GISTSTATE *giststate, Relation r, const Datum *attdata, const bool *isnull, bool isleaf)
 
void gistCompressValues (GISTSTATE *giststate, Relation r, const Datum *attdata, const bool *isnull, bool isleaf, Datum *compatt)
 
OffsetNumber gistchoose (Relation r, Page p, IndexTuple it, GISTSTATE *giststate)
 
void GISTInitBuffer (Buffer b, uint32 f)
 
void gistinitpage (Page page, uint32 f)
 
void gistdentryinit (GISTSTATE *giststate, int nkey, GISTENTRY *e, Datum k, Relation r, Page pg, OffsetNumber o, bool l, bool isNull)
 
float gistpenalty (GISTSTATE *giststate, int attno, GISTENTRY *orig, bool isNullOrig, GISTENTRY *add, bool isNullAdd)
 
void gistMakeUnionItVec (GISTSTATE *giststate, IndexTuple *itvec, int len, Datum *attr, bool *isnull)
 
bool gistKeyIsEQ (GISTSTATE *giststate, int attno, Datum a, Datum b)
 
void gistDeCompressAtt (GISTSTATE *giststate, Relation r, IndexTuple tuple, Page p, OffsetNumber o, GISTENTRY *attdata, bool *isnull)
 
HeapTuple gistFetchTuple (GISTSTATE *giststate, Relation r, IndexTuple tuple)
 
void gistMakeUnionKey (GISTSTATE *giststate, int attno, GISTENTRY *entry1, bool isnull1, GISTENTRY *entry2, bool isnull2, Datum *dst, bool *dstisnull)
 
XLogRecPtr gistGetFakeLSN (Relation rel)
 
IndexBulkDeleteResultgistbulkdelete (IndexVacuumInfo *info, IndexBulkDeleteResult *stats, IndexBulkDeleteCallback callback, void *callback_state)
 
IndexBulkDeleteResultgistvacuumcleanup (IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
 
void gistSplitByKey (Relation r, Page page, IndexTuple *itup, int len, GISTSTATE *giststate, GistSplitVector *v, int attno)
 
IndexBuildResultgistbuild (Relation heap, Relation index, struct IndexInfo *indexInfo)
 
GISTBuildBuffersgistInitBuildBuffers (int pagesPerBuffer, int levelStep, int maxLevel)
 
GISTNodeBuffergistGetNodeBuffer (GISTBuildBuffers *gfbb, GISTSTATE *giststate, BlockNumber nodeBlocknum, int level)
 
void gistPushItupToNodeBuffer (GISTBuildBuffers *gfbb, GISTNodeBuffer *nodeBuffer, IndexTuple itup)
 
bool gistPopItupFromNodeBuffer (GISTBuildBuffers *gfbb, GISTNodeBuffer *nodeBuffer, IndexTuple *itup)
 
void gistFreeBuildBuffers (GISTBuildBuffers *gfbb)
 
void gistRelocateBuildBuffersOnSplit (GISTBuildBuffers *gfbb, GISTSTATE *giststate, Relation r, int level, Buffer buffer, List *splitinfo)
 
void gistUnloadNodeBuffers (GISTBuildBuffers *gfbb)
 

Macro Definition Documentation

◆ BUFFER_HALF_FILLED

#define BUFFER_HALF_FILLED (   nodeBuffer,
  gfbb 
)     ((nodeBuffer)->blocksCount > (gfbb)->pagesPerBuffer / 2)

Definition at line 324 of file gist_private.h.

338{
339 /* Persistent memory context for the buffers and metadata. */
340 MemoryContext context;
341
342 BufFile *pfile; /* Temporary file to store buffers in */
343 long nFileBlocks; /* Current size of the temporary file */
344
345 /*
346 * resizable array of free blocks.
347 */
348 long *freeBlocks;
349 int nFreeBlocks; /* # of currently free blocks in the array */
350 int freeBlocksLen; /* current allocated length of the array */
351
352 /* Hash for buffers by block number */
353 HTAB *nodeBuffersTab;
354
355 /* List of buffers scheduled for emptying */
356 List *bufferEmptyingQueue;
357
358 /*
359 * Parameters to the buffering build algorithm. levelStep determines which
360 * levels in the tree have buffers, and pagesPerBuffer determines how
361 * large each buffer is.
362 */
363 int levelStep;
364 int pagesPerBuffer;
365
366 /* Array of lists of buffers on each level, for final emptying */
367 List **buffersOnLevels;
368 int buffersOnLevelsLen;
369
370 /*
371 * Dynamically-sized array of buffers that currently have their last page
372 * loaded in main memory.
373 */
374 GISTNodeBuffer **loadedBuffers;
375 int loadedBuffersCount; /* # of entries in loadedBuffers */
376 int loadedBuffersLen; /* allocated size of loadedBuffers */
377
378 /* Level of the current root node (= height of the index tree - 1) */
379 int rootlevel;
381
382/* GiSTOptions->buffering_mode values */
383typedef enum GistOptBufferingMode
384{
389
390/*
391 * Storage type for GiST's reloptions
392 */
393typedef struct GiSTOptions
394{
395 int32 vl_len_; /* varlena header (do not touch directly!) */
396 int fillfactor; /* page fill factor in percent (0..100) */
397 GistOptBufferingMode buffering_mode; /* buffering build mode */
399
400/* gist.c */
401extern void gistbuildempty(Relation index);
402extern bool gistinsert(Relation r, Datum *values, bool *isnull,
405 bool indexUnchanged,
406 struct IndexInfo *indexInfo);
409extern void freeGISTstate(GISTSTATE *giststate);
410extern void gistdoinsert(Relation r,
411 IndexTuple itup,
412 Size freespace,
413 GISTSTATE *giststate,
414 Relation heapRel,
415 bool is_build);
416
417/* A List of these is returned from gistplacetopage() in *splitinfo */
418typedef struct
419{
420 Buffer buf; /* the split page "half" */
421 IndexTuple downlink; /* downlink for this half. */
423
424extern bool gistplacetopage(Relation rel, Size freespace, GISTSTATE *giststate,
425 Buffer buffer,
426 IndexTuple *itup, int ntup,
429 List **splitinfo,
430 bool markfollowright,
431 Relation heapRel,
432 bool is_build);
433
434extern SplitPageLayout *gistSplit(Relation r, Page page, IndexTuple *itup,
435 int len, GISTSTATE *giststate);
436
437/* gistxlog.c */
440 OffsetNumber downlinkOffset);
441
442extern void gistXLogPageReuse(Relation rel, Relation heaprel, BlockNumber blkno,
443 FullTransactionId deleteXid);
444
445extern XLogRecPtr gistXLogUpdate(Buffer buffer,
446 OffsetNumber *todelete, int ntodelete,
447 IndexTuple *itup, int ituplen,
449
451 int ntodelete, TransactionId snapshotConflictHorizon,
452 Relation heaprel);
453
456 BlockNumber origrlink, GistNSN orignsn,
457 Buffer leftchildbuf, bool markfollowright);
458
459extern XLogRecPtr gistXLogAssignLSN(void);
460
461/* gistget.c */
462extern bool gistgettuple(IndexScanDesc scan, ScanDirection dir);
463extern int64 gistgetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
464extern bool gistcanreturn(Relation index, int attno);
465
466/* gistvalidate.c */
467extern bool gistvalidate(Oid opclassoid);
469 Oid opclassoid,
470 List *operators,
471 List *functions);
472
473/* gistutil.c */
474
475#define GiSTPageSize \
476 ( BLCKSZ - SizeOfPageHeaderData - MAXALIGN(sizeof(GISTPageOpaqueData)) )
477
478#define GIST_MIN_FILLFACTOR 10
479#define GIST_DEFAULT_FILLFACTOR 90
480
481extern bytea *gistoptions(Datum reloptions, bool validate);
482extern bool gistproperty(Oid index_oid, int attno,
483 IndexAMProperty prop, const char *propname,
484 bool *res, bool *isnull);
485extern bool gistfitpage(IndexTuple *itvec, int len);
486extern bool gistnospace(Page page, IndexTuple *itvec, int len, OffsetNumber todelete, Size freespace);
487extern void gistcheckpage(Relation rel, Buffer buf);
488extern Buffer gistNewBuffer(Relation r, Relation heaprel);
489extern bool gistPageRecyclable(Page page);
490extern void gistfillbuffer(Page page, IndexTuple *itup, int len,
491 OffsetNumber off);
492extern IndexTuple *gistextractpage(Page page, int *len /* out */ );
496
498 int len, GISTSTATE *giststate);
502 GISTSTATE *giststate);
503extern IndexTuple gistFormTuple(GISTSTATE *giststate,
504 Relation r, const Datum *attdata, const bool *isnull, bool isleaf);
505extern void gistCompressValues(GISTSTATE *giststate, Relation r,
506 const Datum *attdata, const bool *isnull, bool isleaf, Datum *compatt);
507
510 GISTSTATE *giststate);
511
512extern void GISTInitBuffer(Buffer b, uint32 f);
513extern void gistinitpage(Page page, uint32 f);
514extern void gistdentryinit(GISTSTATE *giststate, int nkey, GISTENTRY *e,
516 bool l, bool isNull);
517
518extern float gistpenalty(GISTSTATE *giststate, int attno,
520 GISTENTRY *add, bool isNullAdd);
521extern void gistMakeUnionItVec(GISTSTATE *giststate, IndexTuple *itvec, int len,
522 Datum *attr, bool *isnull);
523extern bool gistKeyIsEQ(GISTSTATE *giststate, int attno, Datum a, Datum b);
524extern void gistDeCompressAtt(GISTSTATE *giststate, Relation r, IndexTuple tuple, Page p,
525 OffsetNumber o, GISTENTRY *attdata, bool *isnull);
526extern HeapTuple gistFetchTuple(GISTSTATE *giststate, Relation r,
527 IndexTuple tuple);
528extern void gistMakeUnionKey(GISTSTATE *giststate, int attno,
529 GISTENTRY *entry1, bool isnull1,
530 GISTENTRY *entry2, bool isnull2,
531 Datum *dst, bool *dstisnull);
532
534
535/* gistvacuum.c */
539 void *callback_state);
541 IndexBulkDeleteResult *stats);
542
543/* gistsplit.c */
544extern void gistSplitByKey(Relation r, Page page, IndexTuple *itup,
545 int len, GISTSTATE *giststate,
547 int attno);
548
549/* gistbuild.c */
551 struct IndexInfo *indexInfo);
552
553/* gistbuildbuffers.c */
554extern GISTBuildBuffers *gistInitBuildBuffers(int pagesPerBuffer, int levelStep,
555 int maxLevel);
557 GISTSTATE *giststate,
558 BlockNumber nodeBlocknum, int level);
560 GISTNodeBuffer *nodeBuffer, IndexTuple itup);
562 GISTNodeBuffer *nodeBuffer, IndexTuple *itup);
563extern void gistFreeBuildBuffers(GISTBuildBuffers *gfbb);
565 GISTSTATE *giststate, Relation r,
566 int level, Buffer buffer,
567 List *splitinfo);
568extern void gistUnloadNodeBuffers(GISTBuildBuffers *gfbb);
569
570#endif /* GIST_PRIVATE_H */
IndexAMProperty
Definition amapi.h:39
static bool validate(Port *port, const char *auth)
Definition auth-oauth.c:638
uint32 BlockNumber
Definition block.h:31
static Datum values[MAXATTR]
Definition bootstrap.c:155
int Buffer
Definition buf.h:23
PageData * Page
Definition bufpage.h:81
int64_t int64
Definition c.h:543
int32_t int32
Definition c.h:542
uint32_t uint32
Definition c.h:546
uint32 TransactionId
Definition c.h:666
size_t Size
Definition c.h:619
bool(* IndexBulkDeleteCallback)(ItemPointer itemptr, void *state)
Definition genam.h:93
IndexUniqueCheck
Definition genam.h:122
XLogRecPtr GistNSN
Definition gist.h:63
SplitPageLayout * gistSplit(Relation r, Page page, IndexTuple *itup, int len, GISTSTATE *giststate)
Definition gist.c:1450
GISTSTATE * initGISTstate(Relation index)
Definition gist.c:1537
void gistDeCompressAtt(GISTSTATE *giststate, Relation r, IndexTuple tuple, Page p, OffsetNumber o, GISTENTRY *attdata, bool *isnull)
Definition gistutil.c:296
bytea * gistoptions(Datum reloptions, bool validate)
Definition gistutil.c:912
void gistadjustmembers(Oid opfamilyoid, Oid opclassoid, List *operators, List *functions)
void gistPushItupToNodeBuffer(GISTBuildBuffers *gfbb, GISTNodeBuffer *nodeBuffer, IndexTuple itup)
bool gistinsert(Relation r, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, IndexUniqueCheck checkUnique, bool indexUnchanged, struct IndexInfo *indexInfo)
Definition gist.c:166
XLogRecPtr gistXLogAssignLSN(void)
Definition gistxlog.c:574
void gistdoinsert(Relation r, IndexTuple itup, Size freespace, GISTSTATE *giststate, Relation heapRel, bool is_build)
Definition gist.c:639
void gistRelocateBuildBuffersOnSplit(GISTBuildBuffers *gfbb, GISTSTATE *giststate, Relation r, int level, Buffer buffer, List *splitinfo)
Buffer gistNewBuffer(Relation r, Relation heaprel)
Definition gistutil.c:824
bool gistproperty(Oid index_oid, int attno, IndexAMProperty prop, const char *propname, bool *res, bool *isnull)
Definition gistutil.c:933
GISTBuildBuffers * gistInitBuildBuffers(int pagesPerBuffer, int levelStep, int maxLevel)
XLogRecPtr gistXLogSplit(bool page_is_leaf, SplitPageLayout *dist, BlockNumber origrlink, GistNSN orignsn, Buffer leftchildbuf, bool markfollowright)
Definition gistxlog.c:493
bool gistPageRecyclable(Page page)
Definition gistutil.c:888
void gistMakeUnionKey(GISTSTATE *giststate, int attno, GISTENTRY *entry1, bool isnull1, GISTENTRY *entry2, bool isnull2, Datum *dst, bool *dstisnull)
Definition gistutil.c:233
XLogRecPtr gistXLogPageDelete(Buffer buffer, FullTransactionId xid, Buffer parentBuffer, OffsetNumber downlinkOffset)
Definition gistxlog.c:550
IndexBulkDeleteResult * gistvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
Definition gistvacuum.c:75
XLogRecPtr gistXLogDelete(Buffer buffer, OffsetNumber *todelete, int ntodelete, TransactionId snapshotConflictHorizon, Relation heaprel)
Definition gistxlog.c:668
bool gistvalidate(Oid opclassoid)
bool gistgettuple(IndexScanDesc scan, ScanDirection dir)
Definition gistget.c:613
void gistMakeUnionItVec(GISTSTATE *giststate, IndexTuple *itvec, int len, Datum *attr, bool *isnull)
Definition gistutil.c:155
bool gistnospace(Page page, IndexTuple *itvec, int len, OffsetNumber todelete, Size freespace)
Definition gistutil.c:59
bool gistplacetopage(Relation rel, Size freespace, GISTSTATE *giststate, Buffer buffer, IndexTuple *itup, int ntup, OffsetNumber oldoffnum, BlockNumber *newblkno, Buffer leftchildbuf, List **splitinfo, bool markfollowright, Relation heapRel, bool is_build)
Definition gist.c:231
HeapTuple gistFetchTuple(GISTSTATE *giststate, Relation r, IndexTuple tuple)
Definition gistutil.c:667
bool gistKeyIsEQ(GISTSTATE *giststate, int attno, Datum a, Datum b)
Definition gistutil.c:281
int64 gistgetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
Definition gistget.c:746
void gistfillbuffer(Page page, IndexTuple *itup, int len, OffsetNumber off)
Definition gistutil.c:34
void gistbuildempty(Relation index)
Definition gist.c:140
GistOptBufferingMode
@ GIST_OPTION_BUFFERING_OFF
@ GIST_OPTION_BUFFERING_AUTO
@ GIST_OPTION_BUFFERING_ON
void gistFreeBuildBuffers(GISTBuildBuffers *gfbb)
IndexTuple gistFormTuple(GISTSTATE *giststate, Relation r, const Datum *attdata, const bool *isnull, bool isleaf)
Definition gistutil.c:575
IndexTuple * gistextractpage(Page page, int *len)
Definition gistutil.c:95
void gistdentryinit(GISTSTATE *giststate, int nkey, GISTENTRY *e, Datum k, Relation r, Page pg, OffsetNumber o, bool l, bool isNull)
Definition gistutil.c:547
bool gistfitpage(IndexTuple *itvec, int len)
Definition gistutil.c:79
IndexTuple gistgetadjusted(Relation r, IndexTuple oldtup, IndexTuple addtup, GISTSTATE *giststate)
Definition gistutil.c:316
OffsetNumber gistchoose(Relation r, Page p, IndexTuple it, GISTSTATE *giststate)
Definition gistutil.c:374
IndexBuildResult * gistbuild(Relation heap, Relation index, struct IndexInfo *indexInfo)
Definition gistbuild.c:179
MemoryContext createTempGistContext(void)
Definition gist.c:129
void gistSplitByKey(Relation r, Page page, IndexTuple *itup, int len, GISTSTATE *giststate, GistSplitVector *v, int attno)
Definition gistsplit.c:623
XLogRecPtr gistGetFakeLSN(Relation rel)
Definition gistutil.c:1016
void gistCompressValues(GISTSTATE *giststate, Relation r, const Datum *attdata, const bool *isnull, bool isleaf, Datum *compatt)
Definition gistutil.c:596
void gistXLogPageReuse(Relation rel, Relation heaprel, BlockNumber blkno, FullTransactionId deleteXid)
Definition gistxlog.c:592
IndexTuple * gistjoinvector(IndexTuple *itvec, int *len, IndexTuple *additvec, int addlen)
Definition gistutil.c:114
bool gistcanreturn(Relation index, int attno)
Definition gistget.c:798
XLogRecPtr gistXLogUpdate(Buffer buffer, OffsetNumber *todelete, int ntodelete, IndexTuple *itup, int ituplen, Buffer leftchildbuf)
Definition gistxlog.c:627
void freeGISTstate(GISTSTATE *giststate)
Definition gist.c:1664
bool gistPopItupFromNodeBuffer(GISTBuildBuffers *gfbb, GISTNodeBuffer *nodeBuffer, IndexTuple *itup)
IndexBulkDeleteResult * gistbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, IndexBulkDeleteCallback callback, void *callback_state)
Definition gistvacuum.c:59
void gistinitpage(Page page, uint32 f)
Definition gistutil.c:757
GISTNodeBuffer * gistGetNodeBuffer(GISTBuildBuffers *gfbb, GISTSTATE *giststate, BlockNumber nodeBlocknum, int level)
void gistUnloadNodeBuffers(GISTBuildBuffers *gfbb)
IndexTuple gistunion(Relation r, IndexTuple *itvec, int len, GISTSTATE *giststate)
Definition gistutil.c:219
void GISTInitBuffer(Buffer b, uint32 f)
Definition gistutil.c:773
void gistcheckpage(Relation rel, Buffer buf)
Definition gistutil.c:785
IndexTupleData * gistfillitupvec(IndexTuple *vec, int veclen, int *memlen)
Definition gistutil.c:127
float gistpenalty(GISTSTATE *giststate, int attno, GISTENTRY *orig, bool isNullOrig, GISTENTRY *add, bool isNullAdd)
Definition gistutil.c:724
int b
Definition isn.c:74
int a
Definition isn.c:73
uint16 OffsetNumber
Definition off.h:24
const void size_t len
static char buf[DEFAULT_XLOG_SEG_SIZE]
uint64_t Datum
Definition postgres.h:70
unsigned int Oid
e
static int fb(int x)
static const struct fns functions
Definition regcomp.c:358
ScanDirection
Definition sdir.h:25
GistOptBufferingMode buffering_mode
Definition pg_list.h:54
Definition type.h:96
Definition c.h:706
static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)
uint64 XLogRecPtr
Definition xlogdefs.h:21

◆ BUFFER_OVERFLOWED

#define BUFFER_OVERFLOWED (   nodeBuffer,
  gfbb 
)     ((nodeBuffer)->blocksCount > (gfbb)->pagesPerBuffer)

Definition at line 332 of file gist_private.h.

◆ BUFFER_PAGE_DATA_OFFSET

#define BUFFER_PAGE_DATA_OFFSET   MAXALIGN(offsetof(GISTNodeBufferPage, tupledata))

Definition at line 53 of file gist_private.h.

◆ GIST_DEFAULT_FILLFACTOR

#define GIST_DEFAULT_FILLFACTOR   90

Definition at line 480 of file gist_private.h.

◆ GIST_EXCLUSIVE

#define GIST_EXCLUSIVE   BUFFER_LOCK_EXCLUSIVE

Definition at line 43 of file gist_private.h.

◆ GIST_MAX_SPLIT_PAGES

#define GIST_MAX_SPLIT_PAGES   75

Definition at line 39 of file gist_private.h.

◆ GIST_MIN_FILLFACTOR

#define GIST_MIN_FILLFACTOR   10

Definition at line 479 of file gist_private.h.

◆ GIST_ROOT_BLKNO

#define GIST_ROOT_BLKNO   0

Definition at line 262 of file gist_private.h.

◆ GIST_SHARE

#define GIST_SHARE   BUFFER_LOCK_SHARE

Definition at line 42 of file gist_private.h.

◆ GIST_UNLOCK

#define GIST_UNLOCK   BUFFER_LOCK_UNLOCK

Definition at line 44 of file gist_private.h.

◆ GiSTPageSize

Definition at line 476 of file gist_private.h.

◆ GISTSearchItemIsHeap

#define GISTSearchItemIsHeap (   item)    ((item).blkno == InvalidBlockNumber)

Definition at line 145 of file gist_private.h.

◆ GistTupleIsInvalid

#define GistTupleIsInvalid (   itup)    ( ItemPointerGetOffsetNumber( &((itup)->t_tid) ) == TUPLE_IS_INVALID )

Definition at line 288 of file gist_private.h.

◆ GistTupleSetValid

#define GistTupleSetValid (   itup)    ItemPointerSetOffsetNumber( &((itup)->t_tid), TUPLE_IS_VALID )

Definition at line 289 of file gist_private.h.

◆ LEVEL_HAS_BUFFERS

#define LEVEL_HAS_BUFFERS (   nlevel,
  gfbb 
)
Value:
((nlevel) != 0 && (nlevel) % (gfbb)->levelStep == 0 && \
(nlevel) != (gfbb)->rootlevel)
Datum nlevel(PG_FUNCTION_ARGS)
Definition ltree_op.c:203

Definition at line 319 of file gist_private.h.

◆ PAGE_FREE_SPACE

#define PAGE_FREE_SPACE (   nbp)    (nbp->freespace)

Definition at line 55 of file gist_private.h.

◆ PAGE_IS_EMPTY

#define PAGE_IS_EMPTY (   nbp)    (nbp->freespace == BLCKSZ - BUFFER_PAGE_DATA_OFFSET)

Definition at line 57 of file gist_private.h.

◆ PAGE_NO_SPACE

#define PAGE_NO_SPACE (   nbp,
  itup 
)
Value:
#define PAGE_FREE_SPACE(nbp)
static Size IndexTupleSize(const IndexTupleData *itup)
Definition itup.h:71

Definition at line 59 of file gist_private.h.

◆ SizeOfGISTSearchItem

#define SizeOfGISTSearchItem (   n_distances)

◆ TUPLE_IS_INVALID

#define TUPLE_IS_INVALID   0xfffe

Definition at line 286 of file gist_private.h.

◆ TUPLE_IS_VALID

#define TUPLE_IS_VALID   0xffff

Definition at line 285 of file gist_private.h.

Typedef Documentation

◆ GISTBuildBuffers

◆ GISTInsertStack

◆ GistOptBufferingMode

◆ GiSTOptions

◆ GISTScanOpaque

◆ GISTScanOpaqueData

◆ GISTSearchHeapItem

◆ GISTSearchItem

◆ GistSplitVector

◆ GISTSTATE

◆ gistxlogPage

◆ SplitPageLayout

Enumeration Type Documentation

◆ GistOptBufferingMode

Enumerator
GIST_OPTION_BUFFERING_AUTO 
GIST_OPTION_BUFFERING_ON 
GIST_OPTION_BUFFERING_OFF 

Definition at line 384 of file gist_private.h.

Function Documentation

◆ createTempGistContext()

MemoryContext createTempGistContext ( void  )
extern

Definition at line 129 of file gist.c.

130{
132 "GiST temporary context",
134}
MemoryContext CurrentMemoryContext
Definition mcxt.c:160
#define AllocSetContextCreate
Definition memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition memutils.h:160

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, and CurrentMemoryContext.

Referenced by gist_xlog_startup(), gistbeginscan(), gistbuild(), and gistinsert().

◆ freeGISTstate()

void freeGISTstate ( GISTSTATE giststate)
extern

Definition at line 1664 of file gist.c.

1665{
1666 /* It's sufficient to delete the scanCxt */
1667 MemoryContextDelete(giststate->scanCxt);
1668}
void MemoryContextDelete(MemoryContext context)
Definition mcxt.c:472
MemoryContext scanCxt

References MemoryContextDelete(), and GISTSTATE::scanCxt.

Referenced by gistbuild(), and gistendscan().

◆ gistadjustmembers()

void gistadjustmembers ( Oid  opfamilyoid,
Oid  opclassoid,
List operators,
List functions 
)
extern

Definition at line 288 of file gistvalidate.c.

292{
293 ListCell *lc;
294
295 /*
296 * Operator members of a GiST opfamily should never have hard
297 * dependencies, since their connection to the opfamily depends only on
298 * what the support functions think, and that can be altered. For
299 * consistency, we make all soft dependencies point to the opfamily,
300 * though a soft dependency on the opclass would work as well in the
301 * CREATE OPERATOR CLASS case.
302 */
303 foreach(lc, operators)
304 {
306
307 op->ref_is_hard = false;
308 op->ref_is_family = true;
309 op->refobjid = opfamilyoid;
310 }
311
312 /*
313 * Required support functions should have hard dependencies. Preferably
314 * those are just dependencies on the opclass, but if we're in ALTER
315 * OPERATOR FAMILY, we leave the dependency pointing at the whole
316 * opfamily. (Given that GiST opclasses generally don't share opfamilies,
317 * it seems unlikely to be worth working harder.)
318 */
319 foreach(lc, functions)
320 {
322
323 switch (op->number)
324 {
326 case GIST_UNION_PROC:
329 case GIST_EQUAL_PROC:
330 /* Required support function */
331 op->ref_is_hard = true;
332 break;
336 case GIST_FETCH_PROC:
340 /* Optional, so force it to be a soft family dependency */
341 op->ref_is_hard = false;
342 op->ref_is_family = true;
343 op->refobjid = opfamilyoid;
344 break;
345 default:
348 errmsg("support function number %d is invalid for access method %s",
349 op->number, "gist")));
350 break;
351 }
352 }
353}
int errcode(int sqlerrcode)
Definition elog.c:863
int errmsg(const char *fmt,...)
Definition elog.c:1080
#define ERROR
Definition elog.h:39
#define ereport(elevel,...)
Definition elog.h:150
#define GIST_DECOMPRESS_PROC
Definition gist.h:35
#define GIST_PICKSPLIT_PROC
Definition gist.h:37
#define GIST_CONSISTENT_PROC
Definition gist.h:32
#define GIST_UNION_PROC
Definition gist.h:33
#define GIST_FETCH_PROC
Definition gist.h:40
#define GIST_SORTSUPPORT_PROC
Definition gist.h:42
#define GIST_COMPRESS_PROC
Definition gist.h:34
#define GIST_PENALTY_PROC
Definition gist.h:36
#define GIST_OPTIONS_PROC
Definition gist.h:41
#define GIST_TRANSLATE_CMPTYPE_PROC
Definition gist.h:43
#define GIST_DISTANCE_PROC
Definition gist.h:39
#define GIST_EQUAL_PROC
Definition gist.h:38
#define lfirst(lc)
Definition pg_list.h:172
Oid refobjid
Definition amapi.h:98
bool ref_is_family
Definition amapi.h:97
bool ref_is_hard
Definition amapi.h:96

References ereport, errcode(), errmsg(), ERROR, fb(), functions, GIST_COMPRESS_PROC, GIST_CONSISTENT_PROC, GIST_DECOMPRESS_PROC, GIST_DISTANCE_PROC, GIST_EQUAL_PROC, GIST_FETCH_PROC, GIST_OPTIONS_PROC, GIST_PENALTY_PROC, GIST_PICKSPLIT_PROC, GIST_SORTSUPPORT_PROC, GIST_TRANSLATE_CMPTYPE_PROC, GIST_UNION_PROC, lfirst, OpFamilyMember::number, OpFamilyMember::ref_is_family, OpFamilyMember::ref_is_hard, and OpFamilyMember::refobjid.

Referenced by gisthandler().

◆ gistbuild()

IndexBuildResult * gistbuild ( Relation  heap,
Relation  index,
struct IndexInfo indexInfo 
)
extern

Definition at line 179 of file gistbuild.c.

180{
181 IndexBuildResult *result;
182 double reltuples;
185 int fillfactor;
187 GiSTOptions *options = (GiSTOptions *) index->rd_options;
188
189 /*
190 * We expect to be called exactly once for any index relation. If that's
191 * not the case, big trouble's what we have.
192 */
194 elog(ERROR, "index \"%s\" already contains data",
196
197 buildstate.indexrel = index;
198 buildstate.heaprel = heap;
199 buildstate.sortstate = NULL;
200 buildstate.giststate = initGISTstate(index);
201
202 /*
203 * Create a temporary memory context that is reset once for each tuple
204 * processed. (Note: we don't bother to make this a child of the
205 * giststate's scanCxt, so we have to delete it separately at the end.)
206 */
207 buildstate.giststate->tempCxt = createTempGistContext();
208
209 /*
210 * Choose build strategy. First check whether the user specified to use
211 * buffering mode. (The use-case for that in the field is somewhat
212 * questionable perhaps, but it's important for testing purposes.)
213 */
214 if (options)
215 {
216 if (options->buffering_mode == GIST_OPTION_BUFFERING_ON)
218 else if (options->buffering_mode == GIST_OPTION_BUFFERING_OFF)
220 else /* must be "auto" */
222 }
223 else
224 {
226 }
227
228 /*
229 * Unless buffering mode was forced, see if we can use sorting instead.
230 */
231 if (buildstate.buildMode != GIST_BUFFERING_STATS)
232 {
233 bool hasallsortsupports = true;
235
236 for (int i = 0; i < keyscount; i++)
237 {
241 {
242 hasallsortsupports = false;
243 break;
244 }
245 }
247 buildstate.buildMode = GIST_SORTED_BUILD;
248 }
249
250 /*
251 * Calculate target amount of free space to leave on pages.
252 */
254 buildstate.freespace = BLCKSZ * (100 - fillfactor) / 100;
255
256 /*
257 * Build the index using the chosen strategy.
258 */
259 buildstate.indtuples = 0;
260 buildstate.indtuplesSize = 0;
261
262 if (buildstate.buildMode == GIST_SORTED_BUILD)
263 {
264 /*
265 * Sort all data, build the index from bottom up.
266 */
267 buildstate.sortstate = tuplesort_begin_index_gist(heap,
268 index,
270 NULL,
272
273 /* Scan the table, adding all tuples to the tuplesort */
274 reltuples = table_index_build_scan(heap, index, indexInfo, true, true,
276 &buildstate, NULL);
277
278 /*
279 * Perform the sort and build index pages.
280 */
282
284
285 tuplesort_end(buildstate.sortstate);
286 }
287 else
288 {
289 /*
290 * Initialize an empty index and insert all tuples, possibly using
291 * buffers on intermediate levels.
292 */
293 Buffer buffer;
294 Page page;
295
296 /* initialize the root page */
297 buffer = gistNewBuffer(index, heap);
299 page = BufferGetPage(buffer);
300
302
303 GISTInitBuffer(buffer, F_LEAF);
304
305 MarkBufferDirty(buffer);
307
308 UnlockReleaseBuffer(buffer);
309
311
312 /* Scan the table, inserting all the tuples to the index. */
313 reltuples = table_index_build_scan(heap, index, indexInfo, true, true,
315 &buildstate, NULL);
316
317 /*
318 * If buffering was used, flush out all the tuples that are still in
319 * the buffers.
320 */
321 if (buildstate.buildMode == GIST_BUFFERING_ACTIVE)
322 {
323 elog(DEBUG1, "all tuples processed, emptying buffers");
326 }
327
328 /*
329 * We didn't write WAL records as we built the index, so if
330 * WAL-logging is required, write all pages to the WAL now.
331 */
333 {
336 true);
337 }
338 }
339
340 /* okay, all heap tuples are indexed */
342 MemoryContextDelete(buildstate.giststate->tempCxt);
343
344 freeGISTstate(buildstate.giststate);
345
346 /*
347 * Return statistics
348 */
350
351 result->heap_tuples = reltuples;
352 result->index_tuples = (double) buildstate.indtuples;
353
354 return result;
355}
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition bufmgr.c:4356
void UnlockReleaseBuffer(Buffer buffer)
Definition bufmgr.c:5518
void MarkBufferDirty(Buffer buffer)
Definition bufmgr.c:3056
#define RelationGetNumberOfBlocks(reln)
Definition bufmgr.h:307
static Page BufferGetPage(Buffer buffer)
Definition bufmgr.h:466
static void PageSetLSN(Page page, XLogRecPtr lsn)
Definition bufpage.h:390
#define Assert(condition)
Definition c.h:873
#define OidIsValid(objectId)
Definition c.h:788
#define DEBUG1
Definition elog.h:30
#define elog(elevel,...)
Definition elog.h:226
#define palloc_object(type)
Definition fe_memutils.h:74
GISTSTATE * initGISTstate(Relation index)
Definition gist.c:1537
MemoryContext createTempGistContext(void)
Definition gist.c:129
void freeGISTstate(GISTSTATE *giststate)
Definition gist.c:1664
#define F_LEAF
Definition gist.h:49
#define GistBuildLSN
Definition gist.h:70
#define GIST_ROOT_BLKNO
#define GIST_DEFAULT_FILLFACTOR
@ GIST_BUFFERING_AUTO
Definition gistbuild.c:72
@ GIST_SORTED_BUILD
Definition gistbuild.c:69
@ GIST_BUFFERING_ACTIVE
Definition gistbuild.c:78
@ GIST_BUFFERING_STATS
Definition gistbuild.c:75
@ GIST_BUFFERING_DISABLED
Definition gistbuild.c:70
static void gist_indexsortbuild(GISTBuildState *state)
Definition gistbuild.c:400
static void gistBuildCallback(Relation index, ItemPointer tid, Datum *values, bool *isnull, bool tupleIsAlive, void *state)
Definition gistbuild.c:822
static void gistSortedBuildCallback(Relation index, ItemPointer tid, Datum *values, bool *isnull, bool tupleIsAlive, void *state)
Definition gistbuild.c:366
static void gistEmptyAllBuffers(GISTBuildState *buildstate)
Definition gistbuild.c:1372
void gistFreeBuildBuffers(GISTBuildBuffers *gfbb)
Buffer gistNewBuffer(Relation r, Relation heaprel)
Definition gistutil.c:824
void GISTInitBuffer(Buffer b, uint32 f)
Definition gistutil.c:773
int maintenance_work_mem
Definition globals.c:133
RegProcedure index_getprocid(Relation irel, AttrNumber attnum, uint16 procnum)
Definition indexam.c:883
int i
Definition isn.c:77
#define START_CRIT_SECTION()
Definition miscadmin.h:150
#define END_CRIT_SECTION()
Definition miscadmin.h:152
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
#define INDEX_MAX_KEYS
static int fillfactor
Definition pgbench.c:188
#define RelationGetRelationName(relation)
Definition rel.h:548
#define RelationNeedsWAL(relation)
Definition rel.h:637
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition rel.h:533
@ MAIN_FORKNUM
Definition relpath.h:58
static double table_index_build_scan(Relation table_rel, Relation index_rel, IndexInfo *index_info, bool allow_sync, bool progress, IndexBuildCallback callback, void *callback_state, TableScanDesc scan)
Definition tableam.h:1766
void tuplesort_performsort(Tuplesortstate *state)
Definition tuplesort.c:1348
void tuplesort_end(Tuplesortstate *state)
Definition tuplesort.c:936
#define TUPLESORT_NONE
Definition tuplesort.h:67
Tuplesortstate * tuplesort_begin_index_gist(Relation heapRel, Relation indexRel, int workMem, SortCoordinate coordinate, int sortopt)
void log_newpage_range(Relation rel, ForkNumber forknum, BlockNumber startblk, BlockNumber endblk, bool page_std)

References Assert, BufferGetBlockNumber(), BufferGetPage(), createTempGistContext(), CurrentMemoryContext, DEBUG1, elog, END_CRIT_SECTION, ERROR, F_LEAF, fb(), fillfactor, freeGISTstate(), GIST_BUFFERING_ACTIVE, GIST_BUFFERING_AUTO, GIST_BUFFERING_DISABLED, GIST_BUFFERING_STATS, GIST_DEFAULT_FILLFACTOR, gist_indexsortbuild(), GIST_OPTION_BUFFERING_OFF, GIST_OPTION_BUFFERING_ON, GIST_ROOT_BLKNO, GIST_SORTED_BUILD, GIST_SORTSUPPORT_PROC, gistBuildCallback(), GistBuildLSN, gistEmptyAllBuffers(), gistFreeBuildBuffers(), GISTInitBuffer(), gistNewBuffer(), gistSortedBuildCallback(), IndexBuildResult::heap_tuples, i, index_getprocid(), INDEX_MAX_KEYS, IndexBuildResult::index_tuples, IndexRelationGetNumberOfKeyAttributes, initGISTstate(), log_newpage_range(), MAIN_FORKNUM, maintenance_work_mem, MarkBufferDirty(), MemoryContextDelete(), MemoryContextSwitchTo(), OidIsValid, PageSetLSN(), palloc_object, RelationGetNumberOfBlocks, RelationGetRelationName, RelationNeedsWAL, START_CRIT_SECTION, table_index_build_scan(), tuplesort_begin_index_gist(), tuplesort_end(), TUPLESORT_NONE, tuplesort_performsort(), and UnlockReleaseBuffer().

Referenced by gisthandler().

◆ gistbuildempty()

void gistbuildempty ( Relation  index)
extern

Definition at line 140 of file gist.c.

141{
142 Buffer buffer;
143
144 /* Initialize the root page */
147
148 /* Initialize and xlog buffer */
150 GISTInitBuffer(buffer, F_LEAF);
151 MarkBufferDirty(buffer);
152 log_newpage_buffer(buffer, true);
154
155 /* Unlock and release the buffer */
156 UnlockReleaseBuffer(buffer);
157}
Buffer ExtendBufferedRel(BufferManagerRelation bmr, ForkNumber forkNum, BufferAccessStrategy strategy, uint32 flags)
Definition bufmgr.c:964
@ EB_SKIP_EXTENSION_LOCK
Definition bufmgr.h:75
@ EB_LOCK_FIRST
Definition bufmgr.h:87
#define BMR_REL(p_rel)
Definition bufmgr.h:114
@ INIT_FORKNUM
Definition relpath.h:61
XLogRecPtr log_newpage_buffer(Buffer buffer, bool page_std)

References BMR_REL, EB_LOCK_FIRST, EB_SKIP_EXTENSION_LOCK, END_CRIT_SECTION, ExtendBufferedRel(), F_LEAF, fb(), GISTInitBuffer(), INIT_FORKNUM, log_newpage_buffer(), MarkBufferDirty(), START_CRIT_SECTION, and UnlockReleaseBuffer().

Referenced by gisthandler().

◆ gistbulkdelete()

IndexBulkDeleteResult * gistbulkdelete ( IndexVacuumInfo info,
IndexBulkDeleteResult stats,
IndexBulkDeleteCallback  callback,
void callback_state 
)
extern

Definition at line 59 of file gistvacuum.c.

61{
62 /* allocate stats if first time through, else re-use existing struct */
63 if (stats == NULL)
65
66 gistvacuumscan(info, stats, callback, callback_state);
67
68 return stats;
69}
#define palloc0_object(type)
Definition fe_memutils.h:75
static void gistvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, IndexBulkDeleteCallback callback, void *callback_state)
Definition gistvacuum.c:125

References callback(), fb(), gistvacuumscan(), and palloc0_object.

Referenced by gisthandler().

◆ gistcanreturn()

bool gistcanreturn ( Relation  index,
int  attno 
)
extern

Definition at line 798 of file gistget.c.

799{
803 return true;
804 else
805 return false;
806}

References GIST_COMPRESS_PROC, GIST_FETCH_PROC, index_getprocid(), IndexRelationGetNumberOfKeyAttributes, and OidIsValid.

Referenced by gisthandler().

◆ gistcheckpage()

void gistcheckpage ( Relation  rel,
Buffer  buf 
)
extern

Definition at line 785 of file gistutil.c.

786{
787 Page page = BufferGetPage(buf);
788
789 /*
790 * ReadBuffer verifies that every newly-read page passes
791 * PageHeaderIsValid, which means it either contains a reasonably sane
792 * page header or is all-zero. We have to defend against the all-zero
793 * case, however.
794 */
795 if (PageIsNew(page))
798 errmsg("index \"%s\" contains unexpected zero page at block %u",
801 errhint("Please REINDEX it.")));
802
803 /*
804 * Additionally check that the special area looks sane.
805 */
806 if (PageGetSpecialSize(page) != MAXALIGN(sizeof(GISTPageOpaqueData)))
809 errmsg("index \"%s\" contains corrupted page at block %u",
812 errhint("Please REINDEX it.")));
813}
static uint16 PageGetSpecialSize(const PageData *page)
Definition bufpage.h:316
static bool PageIsNew(const PageData *page)
Definition bufpage.h:233
#define MAXALIGN(LEN)
Definition c.h:826
int errhint(const char *fmt,...)
Definition elog.c:1330

References buf, BufferGetBlockNumber(), BufferGetPage(), ereport, errcode(), errhint(), errmsg(), ERROR, fb(), MAXALIGN, PageGetSpecialSize(), PageIsNew(), and RelationGetRelationName.

Referenced by gistBufferingFindCorrectParent(), gistdoinsert(), gistFindCorrectParent(), gistFindPath(), gistkillitems(), gistNewBuffer(), gistScanPage(), and gistvacuum_delete_empty_pages().

◆ gistchoose()

OffsetNumber gistchoose ( Relation  r,
Page  p,
IndexTuple  it,
GISTSTATE giststate 
)
extern

Definition at line 374 of file gistutil.c.

376{
377 OffsetNumber result;
378 OffsetNumber maxoff;
381 GISTENTRY entry,
383 bool isnull[INDEX_MAX_KEYS];
385
387
388 gistDeCompressAtt(giststate, r,
389 it, NULL, (OffsetNumber) 0,
390 identry, isnull);
391
392 /* we'll return FirstOffsetNumber if page is empty (shouldn't happen) */
393 result = FirstOffsetNumber;
394
395 /*
396 * The index may have multiple columns, and there's a penalty value for
397 * each column. The penalty associated with a column that appears earlier
398 * in the index definition is strictly more important than the penalty of
399 * a column that appears later in the index definition.
400 *
401 * best_penalty[j] is the best penalty we have seen so far for column j,
402 * or -1 when we haven't yet examined column j. Array entries to the
403 * right of the first -1 are undefined.
404 */
405 best_penalty[0] = -1;
406
407 /*
408 * If we find a tuple that's exactly as good as the currently best one, we
409 * could use either one. When inserting a lot of tuples with the same or
410 * similar keys, it's preferable to descend down the same path when
411 * possible, as that's more cache-friendly. On the other hand, if all
412 * inserts land on the same leaf page after a split, we're never going to
413 * insert anything to the other half of the split, and will end up using
414 * only 50% of the available space. Distributing the inserts evenly would
415 * lead to better space usage, but that hurts cache-locality during
416 * insertion. To get the best of both worlds, when we find a tuple that's
417 * exactly as good as the previous best, choose randomly whether to stick
418 * to the old best, or use the new one. Once we decide to stick to the
419 * old best, we keep sticking to it for any subsequent equally good tuples
420 * we might find. This favors tuples with low offsets, but still allows
421 * some inserts to go to other equally-good subtrees.
422 *
423 * keep_current_best is -1 if we haven't yet had to make a random choice
424 * whether to keep the current best tuple. If we have done so, and
425 * decided to keep it, keep_current_best is 1; if we've decided to
426 * replace, keep_current_best is 0. (This state will be reset to -1 as
427 * soon as we've made the replacement, but sometimes we make the choice in
428 * advance of actually finding a replacement best tuple.)
429 */
431
432 /*
433 * Loop over tuples on page.
434 */
435 maxoff = PageGetMaxOffsetNumber(p);
436 Assert(maxoff >= FirstOffsetNumber);
437
438 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
439 {
441 bool zero_penalty;
442 int j;
443
444 zero_penalty = true;
445
446 /* Loop over index attributes. */
447 for (j = 0; j < IndexRelationGetNumberOfKeyAttributes(r); j++)
448 {
449 Datum datum;
450 float usize;
451 bool IsNull;
452
453 /* Compute penalty for this column. */
454 datum = index_getattr(itup, j + 1, giststate->leafTupdesc,
455 &IsNull);
456 gistdentryinit(giststate, j, &entry, datum, r, p, i,
457 false, IsNull);
458 usize = gistpenalty(giststate, j, &entry, IsNull,
459 &identry[j], isnull[j]);
460 if (usize > 0)
461 zero_penalty = false;
462
463 if (best_penalty[j] < 0 || usize < best_penalty[j])
464 {
465 /*
466 * New best penalty for column. Tentatively select this tuple
467 * as the target, and record the best penalty. Then reset the
468 * next column's penalty to "unknown" (and indirectly, the
469 * same for all the ones to its right). This will force us to
470 * adopt this tuple's penalty values as the best for all the
471 * remaining columns during subsequent loop iterations.
472 */
473 result = i;
475
477 best_penalty[j + 1] = -1;
478
479 /* we have new best, so reset keep-it decision */
481 }
482 else if (best_penalty[j] == usize)
483 {
484 /*
485 * The current tuple is exactly as good for this column as the
486 * best tuple seen so far. The next iteration of this loop
487 * will compare the next column.
488 */
489 }
490 else
491 {
492 /*
493 * The current tuple is worse for this column than the best
494 * tuple seen so far. Skip the remaining columns and move on
495 * to the next tuple, if any.
496 */
497 zero_penalty = false; /* so outer loop won't exit */
498 break;
499 }
500 }
501
502 /*
503 * If we looped past the last column, and did not update "result",
504 * then this tuple is exactly as good as the prior best tuple.
505 */
506 if (j == IndexRelationGetNumberOfKeyAttributes(r) && result != i)
507 {
508 if (keep_current_best == -1)
509 {
510 /* we didn't make the random choice yet for this old best */
512 }
513 if (keep_current_best == 0)
514 {
515 /* we choose to use the new tuple */
516 result = i;
517 /* choose again if there are even more exactly-as-good ones */
519 }
520 }
521
522 /*
523 * If we find a tuple with zero penalty for all columns, and we've
524 * decided we don't want to search for another tuple with equal
525 * penalty, there's no need to examine remaining tuples; just break
526 * out of the loop and return it.
527 */
528 if (zero_penalty)
529 {
530 if (keep_current_best == -1)
531 {
532 /* we didn't make the random choice yet for this old best */
534 }
535 if (keep_current_best == 1)
536 break;
537 }
538 }
539
540 return result;
541}
static ItemId PageGetItemId(Page page, OffsetNumber offsetNumber)
Definition bufpage.h:243
static void * PageGetItem(PageData *page, const ItemIdData *itemId)
Definition bufpage.h:353
static OffsetNumber PageGetMaxOffsetNumber(const PageData *page)
Definition bufpage.h:371
#define GistPageIsLeaf(page)
Definition gist.h:170
void gistDeCompressAtt(GISTSTATE *giststate, Relation r, IndexTuple tuple, Page p, OffsetNumber o, GISTENTRY *attdata, bool *isnull)
Definition gistutil.c:296
void gistdentryinit(GISTSTATE *giststate, int nkey, GISTENTRY *e, Datum k, Relation r, Page pg, OffsetNumber o, bool l, bool isNull)
Definition gistutil.c:547
float gistpenalty(GISTSTATE *giststate, int attno, GISTENTRY *orig, bool isNullOrig, GISTENTRY *add, bool isNullAdd)
Definition gistutil.c:724
int j
Definition isn.c:78
IndexTupleData * IndexTuple
Definition itup.h:53
static Datum index_getattr(IndexTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition itup.h:131
#define OffsetNumberNext(offsetNumber)
Definition off.h:52
#define FirstOffsetNumber
Definition off.h:27
pg_prng_state pg_global_prng_state
Definition pg_prng.c:34
bool pg_prng_bool(pg_prng_state *state)
Definition pg_prng.c:313
TupleDesc leafTupdesc

References Assert, fb(), FirstOffsetNumber, gistDeCompressAtt(), gistdentryinit(), GistPageIsLeaf, gistpenalty(), i, index_getattr(), INDEX_MAX_KEYS, IndexRelationGetNumberOfKeyAttributes, j, GISTSTATE::leafTupdesc, OffsetNumberNext, PageGetItem(), PageGetItemId(), PageGetMaxOffsetNumber(), pg_global_prng_state, and pg_prng_bool().

Referenced by gistdoinsert(), and gistProcessItup().

◆ gistCompressValues()

void gistCompressValues ( GISTSTATE giststate,
Relation  r,
const Datum attdata,
const bool isnull,
bool  isleaf,
Datum compatt 
)
extern

Definition at line 596 of file gistutil.c.

598{
599 int i;
600
601 /*
602 * Call the compress method on each attribute.
603 */
604 for (i = 0; i < IndexRelationGetNumberOfKeyAttributes(r); i++)
605 {
606 if (isnull[i])
607 compatt[i] = (Datum) 0;
608 else
609 {
611 GISTENTRY *cep;
612
614 isleaf);
615 /* there may not be a compress function in opclass */
616 if (OidIsValid(giststate->compressFn[i].fn_oid))
617 cep = (GISTENTRY *)
619 giststate->supportCollation[i],
621 else
622 cep = &centry;
623 compatt[i] = cep->key;
624 }
625 }
626
627 if (isleaf)
628 {
629 /*
630 * Emplace each included attribute if any.
631 */
632 for (; i < r->rd_att->natts; i++)
633 {
634 if (isnull[i])
635 compatt[i] = (Datum) 0;
636 else
637 compatt[i] = attdata[i];
638 }
639 }
640}
Datum FunctionCall1Coll(FmgrInfo *flinfo, Oid collation, Datum arg1)
Definition fmgr.c:1130
#define gistentryinit(e, k, r, pg, o, l)
Definition gist.h:245
static Datum PointerGetDatum(const void *X)
Definition postgres.h:352
static Pointer DatumGetPointer(Datum X)
Definition postgres.h:342
Oid fn_oid
Definition fmgr.h:59
Oid supportCollation[INDEX_MAX_KEYS]
FmgrInfo compressFn[INDEX_MAX_KEYS]
TupleDesc rd_att
Definition rel.h:112

References GISTSTATE::compressFn, DatumGetPointer(), fb(), FmgrInfo::fn_oid, FunctionCall1Coll(), gistentryinit, i, IndexRelationGetNumberOfKeyAttributes, TupleDescData::natts, OidIsValid, PointerGetDatum(), RelationData::rd_att, and GISTSTATE::supportCollation.

Referenced by gistFormTuple(), and gistSortedBuildCallback().

◆ gistDeCompressAtt()

void gistDeCompressAtt ( GISTSTATE giststate,
Relation  r,
IndexTuple  tuple,
Page  p,
OffsetNumber  o,
GISTENTRY attdata,
bool isnull 
)
extern

Definition at line 296 of file gistutil.c.

298{
299 int i;
300
301 for (i = 0; i < IndexRelationGetNumberOfKeyAttributes(r); i++)
302 {
303 Datum datum;
304
305 datum = index_getattr(tuple, i + 1, giststate->leafTupdesc, &isnull[i]);
306 gistdentryinit(giststate, i, &attdata[i],
307 datum, r, p, o,
308 false, isnull[i]);
309 }
310}

References fb(), gistdentryinit(), i, index_getattr(), IndexRelationGetNumberOfKeyAttributes, and GISTSTATE::leafTupdesc.

Referenced by gistchoose(), gistgetadjusted(), gistRelocateBuildBuffersOnSplit(), and placeOne().

◆ gistdentryinit()

void gistdentryinit ( GISTSTATE giststate,
int  nkey,
GISTENTRY e,
Datum  k,
Relation  r,
Page  pg,
OffsetNumber  o,
bool  l,
bool  isNull 
)
extern

Definition at line 547 of file gistutil.c.

550{
551 if (!isNull)
552 {
553 GISTENTRY *dep;
554
555 gistentryinit(*e, k, r, pg, o, l);
556
557 /* there may not be a decompress function in opclass */
558 if (!OidIsValid(giststate->decompressFn[nkey].fn_oid))
559 return;
560
561 dep = (GISTENTRY *)
563 giststate->supportCollation[nkey],
565 /* decompressFn may just return the given pointer */
566 if (dep != e)
567 gistentryinit(*e, dep->key, dep->rel, dep->page, dep->offset,
568 dep->leafkey);
569 }
570 else
571 gistentryinit(*e, (Datum) 0, r, pg, o, l);
572}
FmgrInfo decompressFn[INDEX_MAX_KEYS]

References DatumGetPointer(), GISTSTATE::decompressFn, fb(), FmgrInfo::fn_oid, FunctionCall1Coll(), gistentryinit, OidIsValid, PointerGetDatum(), and GISTSTATE::supportCollation.

Referenced by gistchoose(), gistDeCompressAtt(), gistindex_keytest(), gistMakeUnionItVec(), and gistSplitByKey().

◆ gistdoinsert()

void gistdoinsert ( Relation  r,
IndexTuple  itup,
Size  freespace,
GISTSTATE giststate,
Relation  heapRel,
bool  is_build 
)
extern

Definition at line 639 of file gist.c.

641{
642 ItemId iid;
645 GISTInsertStack *stack;
647 bool xlocked = false;
648
649 memset(&state, 0, sizeof(GISTInsertState));
650 state.freespace = freespace;
651 state.r = r;
652 state.heapRel = heapRel;
653 state.is_build = is_build;
654
655 /* Start from the root */
658 firststack.retry_from_parent = false;
659 firststack.parent = NULL;
660 firststack.downlinkoffnum = InvalidOffsetNumber;
661 state.stack = stack = &firststack;
662
663 /*
664 * Walk down along the path of smallest penalty, updating the parent
665 * pointers with the key we're inserting as we go. If we crash in the
666 * middle, the tree is consistent, although the possible parent updates
667 * were a waste.
668 */
669 for (;;)
670 {
671 /*
672 * If we split an internal page while descending the tree, we have to
673 * retry at the parent. (Normally, the LSN-NSN interlock below would
674 * also catch this and cause us to retry. But LSNs are not updated
675 * during index build.)
676 */
677 while (stack->retry_from_parent)
678 {
679 if (xlocked)
681 xlocked = false;
682 ReleaseBuffer(stack->buffer);
683 state.stack = stack = stack->parent;
684 }
685
686 if (!XLogRecPtrIsValid(stack->lsn))
687 stack->buffer = ReadBuffer(state.r, stack->blkno);
688
689 /*
690 * Be optimistic and grab shared lock first. Swap it for an exclusive
691 * lock later if we need to update the page.
692 */
693 if (!xlocked)
694 {
696 gistcheckpage(state.r, stack->buffer);
697 }
698
699 stack->page = BufferGetPage(stack->buffer);
700 stack->lsn = xlocked ?
701 PageGetLSN(stack->page) : BufferGetLSNAtomic(stack->buffer);
703
704 /*
705 * If this page was split but the downlink was never inserted to the
706 * parent because the inserting backend crashed before doing that, fix
707 * that now.
708 */
709 if (GistFollowRight(stack->page))
710 {
711 if (!xlocked)
712 {
715 xlocked = true;
716 /* someone might've completed the split when we unlocked */
717 if (!GistFollowRight(stack->page))
718 continue;
719 }
720 gistfixsplit(&state, giststate);
721
723 xlocked = false;
724 state.stack = stack = stack->parent;
725 continue;
726 }
727
728 if ((stack->blkno != GIST_ROOT_BLKNO &&
729 stack->parent->lsn < GistPageGetNSN(stack->page)) ||
730 GistPageIsDeleted(stack->page))
731 {
732 /*
733 * Concurrent split or page deletion detected. There's no
734 * guarantee that the downlink for this page is consistent with
735 * the tuple we're inserting anymore, so go back to parent and
736 * rechoose the best child.
737 */
739 xlocked = false;
740 state.stack = stack = stack->parent;
741 continue;
742 }
743
744 if (!GistPageIsLeaf(stack->page))
745 {
746 /*
747 * This is an internal page so continue to walk down the tree.
748 * Find the child node that has the minimum insertion penalty.
749 */
750 BlockNumber childblkno;
752 GISTInsertStack *item;
753 OffsetNumber downlinkoffnum;
754
755 downlinkoffnum = gistchoose(state.r, stack->page, itup, giststate);
756 iid = PageGetItemId(stack->page, downlinkoffnum);
758 childblkno = ItemPointerGetBlockNumber(&(idxtuple->t_tid));
759
760 /*
761 * Check that it's not a leftover invalid tuple from pre-9.1
762 */
765 (errmsg("index \"%s\" contains an inner tuple marked as invalid",
767 errdetail("This is caused by an incomplete page split at crash recovery before upgrading to PostgreSQL 9.1."),
768 errhint("Please REINDEX it.")));
769
770 /*
771 * Check that the key representing the target child node is
772 * consistent with the key we're inserting. Update it if it's not.
773 */
774 newtup = gistgetadjusted(state.r, idxtuple, itup, giststate);
775 if (newtup)
776 {
777 /*
778 * Swap shared lock for an exclusive one. Beware, the page may
779 * change while we unlock/lock the page...
780 */
781 if (!xlocked)
782 {
785 xlocked = true;
786 stack->page = BufferGetPage(stack->buffer);
787
788 if (PageGetLSN(stack->page) != stack->lsn)
789 {
790 /* the page was changed while we unlocked it, retry */
791 continue;
792 }
793 }
794
795 /*
796 * Update the tuple.
797 *
798 * We still hold the lock after gistinserttuple(), but it
799 * might have to split the page to make the updated tuple fit.
800 * In that case the updated tuple might migrate to the other
801 * half of the split, so we have to go back to the parent and
802 * descend back to the half that's a better fit for the new
803 * tuple.
804 */
805 if (gistinserttuple(&state, stack, giststate, newtup,
806 downlinkoffnum))
807 {
808 /*
809 * If this was a root split, the root page continues to be
810 * the parent and the updated tuple went to one of the
811 * child pages, so we just need to retry from the root
812 * page.
813 */
814 if (stack->blkno != GIST_ROOT_BLKNO)
815 {
817 xlocked = false;
818 state.stack = stack = stack->parent;
819 }
820 continue;
821 }
822 }
824 xlocked = false;
825
826 /* descend to the chosen child */
828 item->blkno = childblkno;
829 item->parent = stack;
830 item->downlinkoffnum = downlinkoffnum;
831 state.stack = stack = item;
832 }
833 else
834 {
835 /*
836 * Leaf page. Insert the new key. We've already updated all the
837 * parents on the way down, but we might have to split the page if
838 * it doesn't fit. gistinserttuple() will take care of that.
839 */
840
841 /*
842 * Swap shared lock for an exclusive one. Be careful, the page may
843 * change while we unlock/lock the page...
844 */
845 if (!xlocked)
846 {
849 xlocked = true;
850 stack->page = BufferGetPage(stack->buffer);
851 stack->lsn = PageGetLSN(stack->page);
852
853 if (stack->blkno == GIST_ROOT_BLKNO)
854 {
855 /*
856 * the only page that can become inner instead of leaf is
857 * the root page, so for root we should recheck it
858 */
859 if (!GistPageIsLeaf(stack->page))
860 {
861 /*
862 * very rare situation: during unlock/lock index with
863 * number of pages = 1 was increased
864 */
866 xlocked = false;
867 continue;
868 }
869
870 /*
871 * we don't need to check root split, because checking
872 * leaf/inner is enough to recognize split for root
873 */
874 }
875 else if ((GistFollowRight(stack->page) ||
876 stack->parent->lsn < GistPageGetNSN(stack->page)) ||
877 GistPageIsDeleted(stack->page))
878 {
879 /*
880 * The page was split or deleted while we momentarily
881 * unlocked the page. Go back to parent.
882 */
884 xlocked = false;
885 state.stack = stack = stack->parent;
886 continue;
887 }
888 }
889
890 /* now state.stack->(page, buffer and blkno) points to leaf page */
891
892 gistinserttuple(&state, stack, giststate, itup,
895
896 /* Release any pins we might still hold before exiting */
897 for (; stack; stack = stack->parent)
898 ReleaseBuffer(stack->buffer);
899 break;
900 }
901 }
902}
void ReleaseBuffer(Buffer buffer)
Definition bufmgr.c:5501
XLogRecPtr BufferGetLSNAtomic(Buffer buffer)
Definition bufmgr.c:4634
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition bufmgr.c:864
static void LockBuffer(Buffer buffer, BufferLockMode mode)
Definition bufmgr.h:328
static XLogRecPtr PageGetLSN(const PageData *page)
Definition bufpage.h:385
int errdetail(const char *fmt,...)
Definition elog.c:1216
static void gistfixsplit(GISTInsertState *state, GISTSTATE *giststate)
Definition gist.c:1200
static bool gistinserttuple(GISTInsertState *state, GISTInsertStack *stack, GISTSTATE *giststate, IndexTuple tuple, OffsetNumber oldoffnum)
Definition gist.c:1260
#define GistFollowRight(page)
Definition gist.h:183
#define GistPageIsDeleted(page)
Definition gist.h:173
#define GistPageGetNSN(page)
Definition gist.h:187
#define GIST_UNLOCK
#define GIST_EXCLUSIVE
#define GistTupleIsInvalid(itup)
#define GIST_SHARE
IndexTuple gistgetadjusted(Relation r, IndexTuple oldtup, IndexTuple addtup, GISTSTATE *giststate)
Definition gistutil.c:316
OffsetNumber gistchoose(Relation r, Page p, IndexTuple it, GISTSTATE *giststate)
Definition gistutil.c:374
void gistcheckpage(Relation rel, Buffer buf)
Definition gistutil.c:785
static BlockNumber ItemPointerGetBlockNumber(const ItemPointerData *pointer)
Definition itemptr.h:103
#define InvalidOffsetNumber
Definition off.h:26
BlockNumber blkno
OffsetNumber downlinkoffnum
struct GISTInsertStack * parent
#define XLogRecPtrIsValid(r)
Definition xlogdefs.h:29
#define InvalidXLogRecPtr
Definition xlogdefs.h:28

References Assert, GISTInsertStack::blkno, GISTInsertStack::buffer, BufferGetLSNAtomic(), BufferGetPage(), GISTInsertStack::downlinkoffnum, ereport, errdetail(), errhint(), errmsg(), ERROR, fb(), GIST_EXCLUSIVE, GIST_ROOT_BLKNO, GIST_SHARE, GIST_UNLOCK, gistcheckpage(), gistchoose(), gistfixsplit(), GistFollowRight, gistgetadjusted(), gistinserttuple(), GistPageGetNSN, GistPageIsDeleted, GistPageIsLeaf, GistTupleIsInvalid, InvalidOffsetNumber, InvalidXLogRecPtr, ItemPointerGetBlockNumber(), LockBuffer(), GISTInsertStack::lsn, GISTInsertStack::page, PageGetItem(), PageGetItemId(), PageGetLSN(), palloc0_object, GISTInsertStack::parent, ReadBuffer(), RelationGetRelationName, RelationNeedsWAL, ReleaseBuffer(), GISTInsertStack::retry_from_parent, UnlockReleaseBuffer(), and XLogRecPtrIsValid.

Referenced by gistBuildCallback(), and gistinsert().

◆ gistextractpage()

IndexTuple * gistextractpage ( Page  page,
int len 
)
extern

Definition at line 95 of file gistutil.c.

96{
98 maxoff;
100
101 maxoff = PageGetMaxOffsetNumber(page);
102 *len = maxoff;
103 itvec = palloc_array(IndexTuple, maxoff);
104 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
106
107 return itvec;
108}
#define palloc_array(type, count)
Definition fe_memutils.h:76

References fb(), FirstOffsetNumber, i, len, OffsetNumberNext, PageGetItem(), PageGetItemId(), PageGetMaxOffsetNumber(), and palloc_array.

Referenced by gist_indexsortbuild_levelstate_flush(), and gistplacetopage().

◆ gistFetchTuple()

HeapTuple gistFetchTuple ( GISTSTATE giststate,
Relation  r,
IndexTuple  tuple 
)
extern

Definition at line 667 of file gistutil.c.

668{
671 bool isnull[INDEX_MAX_KEYS];
672 int i;
673
674 for (i = 0; i < IndexRelationGetNumberOfKeyAttributes(r); i++)
675 {
676 Datum datum;
677
678 datum = index_getattr(tuple, i + 1, giststate->leafTupdesc, &isnull[i]);
679
680 if (giststate->fetchFn[i].fn_oid != InvalidOid)
681 {
682 if (!isnull[i])
683 fetchatt[i] = gistFetchAtt(giststate, i, datum, r);
684 else
685 fetchatt[i] = (Datum) 0;
686 }
687 else if (giststate->compressFn[i].fn_oid == InvalidOid)
688 {
689 /*
690 * If opclass does not provide compress method that could change
691 * original value, att is necessarily stored in original form.
692 */
693 if (!isnull[i])
694 fetchatt[i] = datum;
695 else
696 fetchatt[i] = (Datum) 0;
697 }
698 else
699 {
700 /*
701 * Index-only scans not supported for this column. Since the
702 * planner chose an index-only scan anyway, it is not interested
703 * in this column, and we can replace it with a NULL.
704 */
705 isnull[i] = true;
706 fetchatt[i] = (Datum) 0;
707 }
708 }
709
710 /*
711 * Get each included attribute.
712 */
713 for (; i < r->rd_att->natts; i++)
714 {
715 fetchatt[i] = index_getattr(tuple, i + 1, giststate->leafTupdesc,
716 &isnull[i]);
717 }
719
720 return heap_form_tuple(giststate->fetchTupdesc, fetchatt, isnull);
721}
static Datum gistFetchAtt(GISTSTATE *giststate, int nkey, Datum k, Relation r)
Definition gistutil.c:646
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition heaptuple.c:1117
#define InvalidOid
FmgrInfo fetchFn[INDEX_MAX_KEYS]
TupleDesc fetchTupdesc
MemoryContext tempCxt
#define fetchatt(A, T)
Definition tupmacs.h:44

References GISTSTATE::compressFn, fb(), fetchatt, GISTSTATE::fetchFn, GISTSTATE::fetchTupdesc, FmgrInfo::fn_oid, gistFetchAtt(), heap_form_tuple(), i, index_getattr(), INDEX_MAX_KEYS, IndexRelationGetNumberOfKeyAttributes, InvalidOid, GISTSTATE::leafTupdesc, MemoryContextSwitchTo(), TupleDescData::natts, RelationData::rd_att, and GISTSTATE::tempCxt.

Referenced by gistScanPage().

◆ gistfillbuffer()

void gistfillbuffer ( Page  page,
IndexTuple itup,
int  len,
OffsetNumber  off 
)
extern

Definition at line 34 of file gistutil.c.

35{
36 int i;
37
38 if (off == InvalidOffsetNumber)
39 off = (PageIsEmpty(page)) ? FirstOffsetNumber :
41
42 for (i = 0; i < len; i++)
43 {
44 Size sz = IndexTupleSize(itup[i]);
46
47 l = PageAddItem(page, itup[i], sz, off, false, false);
48 if (l == InvalidOffsetNumber)
49 elog(ERROR, "failed to add item to GiST index page, item %d out of %d, size %zu bytes",
50 i, len, sz);
51 off++;
52 }
53}
static bool PageIsEmpty(const PageData *page)
Definition bufpage.h:223
#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap)
Definition bufpage.h:471

References elog, ERROR, fb(), FirstOffsetNumber, i, IndexTupleSize(), InvalidOffsetNumber, len, OffsetNumberNext, PageAddItem, PageGetMaxOffsetNumber(), and PageIsEmpty().

Referenced by gist_indexsortbuild_levelstate_add(), gistplacetopage(), and gistRedoPageSplitRecord().

◆ gistfillitupvec()

IndexTupleData * gistfillitupvec ( IndexTuple vec,
int  veclen,
int memlen 
)
extern

Definition at line 127 of file gistutil.c.

128{
129 char *ptr,
130 *ret;
131 int i;
132
133 *memlen = 0;
134
135 for (i = 0; i < veclen; i++)
137
138 ptr = ret = palloc(*memlen);
139
140 for (i = 0; i < veclen; i++)
141 {
142 memcpy(ptr, vec[i], IndexTupleSize(vec[i]));
143 ptr += IndexTupleSize(vec[i]);
144 }
145
146 return (IndexTupleData *) ret;
147}
void * palloc(Size size)
Definition mcxt.c:1387

References fb(), i, IndexTupleSize(), and palloc().

Referenced by gist_indexsortbuild_levelstate_flush(), gistplacetopage(), and gistSplit().

◆ gistfitpage()

bool gistfitpage ( IndexTuple itvec,
int  len 
)
extern

Definition at line 79 of file gistutil.c.

80{
81 int i;
82 Size size = 0;
83
84 for (i = 0; i < len; i++)
85 size += IndexTupleSize(itvec[i]) + sizeof(ItemIdData);
86
87 /* TODO: Consider fillfactor */
88 return (size <= GiSTPageSize);
89}
#define GiSTPageSize

References fb(), GiSTPageSize, i, IndexTupleSize(), and len.

Referenced by gistSplit().

◆ gistFormTuple()

IndexTuple gistFormTuple ( GISTSTATE giststate,
Relation  r,
const Datum attdata,
const bool isnull,
bool  isleaf 
)
extern

Definition at line 575 of file gistutil.c.

577{
579 IndexTuple res;
580
581 gistCompressValues(giststate, r, attdata, isnull, isleaf, compatt);
582
583 res = index_form_tuple(isleaf ? giststate->leafTupdesc :
584 giststate->nonLeafTupdesc,
585 compatt, isnull);
586
587 /*
588 * The offset number on tuples on internal pages is unused. For historical
589 * reasons, it is set to 0xffff.
590 */
591 ItemPointerSetOffsetNumber(&(res->t_tid), 0xffff);
592 return res;
593}
void gistCompressValues(GISTSTATE *giststate, Relation r, const Datum *attdata, const bool *isnull, bool isleaf, Datum *compatt)
Definition gistutil.c:596
IndexTuple index_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition indextuple.c:44
static void ItemPointerSetOffsetNumber(ItemPointerData *pointer, OffsetNumber offsetNumber)
Definition itemptr.h:158
ItemPointerData t_tid
Definition itup.h:37

References fb(), gistCompressValues(), index_form_tuple(), INDEX_MAX_KEYS, ItemPointerSetOffsetNumber(), GISTSTATE::leafTupdesc, GISTSTATE::nonLeafTupdesc, and IndexTupleData::t_tid.

Referenced by gistBuildCallback(), gistgetadjusted(), gistinsert(), gistSplit(), and gistunion().

◆ gistFreeBuildBuffers()

void gistFreeBuildBuffers ( GISTBuildBuffers gfbb)
extern

Definition at line 505 of file gistbuildbuffers.c.

506{
507 /* Close buffers file. */
508 BufFileClose(gfbb->pfile);
509
510 /* All other things will be freed on memory context release */
511}
void BufFileClose(BufFile *file)
Definition buffile.c:412

References BufFileClose(), and GISTBuildBuffers::pfile.

Referenced by gistbuild().

◆ gistgetadjusted()

IndexTuple gistgetadjusted ( Relation  r,
IndexTuple  oldtup,
IndexTuple  addtup,
GISTSTATE giststate 
)
extern

Definition at line 316 of file gistutil.c.

317{
318 bool neednew = false;
323 Datum attr[INDEX_MAX_KEYS];
324 bool isnull[INDEX_MAX_KEYS];
326 int i;
327
328 gistDeCompressAtt(giststate, r, oldtup, NULL,
330
331 gistDeCompressAtt(giststate, r, addtup, NULL,
333
334 for (i = 0; i < IndexRelationGetNumberOfKeyAttributes(r); i++)
335 {
336 gistMakeUnionKey(giststate, i,
339 attr + i, isnull + i);
340
341 if (neednew)
342 /* we already need new key, so we can skip check */
343 continue;
344
345 if (isnull[i])
346 /* union of key may be NULL if and only if both keys are NULL */
347 continue;
348
349 if (!addisnull[i])
350 {
351 if (oldisnull[i] ||
352 !gistKeyIsEQ(giststate, i, oldentries[i].key, attr[i]))
353 neednew = true;
354 }
355 }
356
357 if (neednew)
358 {
359 /* need to update key */
360 newtup = gistFormTuple(giststate, r, attr, isnull, false);
361 newtup->t_tid = oldtup->t_tid;
362 }
363
364 return newtup;
365}
void gistMakeUnionKey(GISTSTATE *giststate, int attno, GISTENTRY *entry1, bool isnull1, GISTENTRY *entry2, bool isnull2, Datum *dst, bool *dstisnull)
Definition gistutil.c:233
bool gistKeyIsEQ(GISTSTATE *giststate, int attno, Datum a, Datum b)
Definition gistutil.c:281
IndexTuple gistFormTuple(GISTSTATE *giststate, Relation r, const Datum *attdata, const bool *isnull, bool isleaf)
Definition gistutil.c:575

References fb(), gistDeCompressAtt(), gistFormTuple(), gistKeyIsEQ(), gistMakeUnionKey(), i, INDEX_MAX_KEYS, and IndexRelationGetNumberOfKeyAttributes.

Referenced by gistdoinsert(), gistformdownlink(), gistProcessItup(), and gistRelocateBuildBuffersOnSplit().

◆ gistgetbitmap()

int64 gistgetbitmap ( IndexScanDesc  scan,
TIDBitmap tbm 
)
extern

Definition at line 746 of file gistget.c.

747{
749 int64 ntids = 0;
751
752 if (!so->qual_ok)
753 return 0;
754
756 if (scan->instrument)
757 scan->instrument->nsearches++;
758
759 /* Begin the scan by processing the root page */
760 so->curPageData = so->nPageData = 0;
761 scan->xs_hitup = NULL;
762 if (so->pageDataCxt)
763 MemoryContextReset(so->pageDataCxt);
764
766 memset(&fakeItem.data.parentlsn, 0, sizeof(GistNSN));
767 gistScanPage(scan, &fakeItem, NULL, tbm, &ntids);
768
769 /*
770 * While scanning a leaf page, ItemPointers of matching heap tuples will
771 * be stored directly into tbm, so we don't need to deal with them here.
772 */
773 for (;;)
774 {
776
777 if (!item)
778 break;
779
781
782 gistScanPage(scan, item, item->distances, tbm, &ntids);
783
784 pfree(item);
785 }
786
787 return ntids;
788}
GISTScanOpaqueData * GISTScanOpaque
static GISTSearchItem * getNextGISTSearchItem(GISTScanOpaque so)
Definition gistget.c:539
static void gistScanPage(IndexScanDesc scan, GISTSearchItem *pageItem, IndexOrderByDistance *myDistances, TIDBitmap *tbm, int64 *ntids)
Definition gistget.c:329
void MemoryContextReset(MemoryContext context)
Definition mcxt.c:403
void pfree(void *pointer)
Definition mcxt.c:1616
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:123
#define pgstat_count_index_scan(rel)
Definition pgstat.h:705
IndexOrderByDistance distances[FLEXIBLE_ARRAY_MEMBER]
HeapTuple xs_hitup
Definition relscan.h:170
struct IndexScanInstrumentation * instrument
Definition relscan.h:160
Relation indexRelation
Definition relscan.h:138

References CHECK_FOR_INTERRUPTS, GISTSearchItem::distances, fb(), getNextGISTSearchItem(), GIST_ROOT_BLKNO, gistScanPage(), IndexScanDescData::indexRelation, IndexScanDescData::instrument, MemoryContextReset(), IndexScanInstrumentation::nsearches, IndexScanDescData::opaque, pfree(), pgstat_count_index_scan, and IndexScanDescData::xs_hitup.

Referenced by gisthandler().

◆ gistGetFakeLSN()

XLogRecPtr gistGetFakeLSN ( Relation  rel)
extern

Definition at line 1016 of file gistutil.c.

1017{
1018 if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
1019 {
1020 /*
1021 * Temporary relations are only accessible in our session, so a simple
1022 * backend-local counter will do.
1023 */
1024 static XLogRecPtr counter = FirstNormalUnloggedLSN;
1025
1026 return counter++;
1027 }
1028 else if (RelationIsPermanent(rel))
1029 {
1030 /*
1031 * WAL-logging on this relation will start after commit, so its LSNs
1032 * must be distinct numbers smaller than the LSN at the next commit.
1033 * Emit a dummy WAL record if insert-LSN hasn't advanced after the
1034 * last call.
1035 */
1038
1039 /* Shouldn't be called for WAL-logging relations */
1040 Assert(!RelationNeedsWAL(rel));
1041
1042 /* No need for an actual record if we already have a distinct LSN */
1045
1046 lastlsn = currlsn;
1047 return currlsn;
1048 }
1049 else
1050 {
1051 /*
1052 * Unlogged relations are accessible from other backends, and survive
1053 * (clean) restarts. GetFakeLSNForUnloggedRel() handles that for us.
1054 */
1055 Assert(rel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED);
1056 return GetFakeLSNForUnloggedRel();
1057 }
1058}
XLogRecPtr gistXLogAssignLSN(void)
Definition gistxlog.c:574
#define RelationIsPermanent(relation)
Definition rel.h:626
Form_pg_class rd_rel
Definition rel.h:111
XLogRecPtr GetXLogInsertRecPtr(void)
Definition xlog.c:9598
XLogRecPtr GetFakeLSNForUnloggedRel(void)
Definition xlog.c:4676
#define FirstNormalUnloggedLSN
Definition xlogdefs.h:37

References Assert, fb(), FirstNormalUnloggedLSN, GetFakeLSNForUnloggedRel(), GetXLogInsertRecPtr(), gistXLogAssignLSN(), InvalidXLogRecPtr, RelationData::rd_rel, RelationIsPermanent, RelationNeedsWAL, and XLogRecPtrIsValid.

Referenced by gistdeletepage(), gistplacetopage(), gistprunepage(), gistvacuumpage(), and gistvacuumscan().

◆ gistGetNodeBuffer()

GISTNodeBuffer * gistGetNodeBuffer ( GISTBuildBuffers gfbb,
GISTSTATE giststate,
BlockNumber  nodeBlocknum,
int  level 
)
extern

Definition at line 111 of file gistbuildbuffers.c.

113{
114 GISTNodeBuffer *nodeBuffer;
115 bool found;
116
117 /* Find node buffer in hash table */
118 nodeBuffer = (GISTNodeBuffer *) hash_search(gfbb->nodeBuffersTab,
119 &nodeBlocknum,
121 &found);
122 if (!found)
123 {
124 /*
125 * Node buffer wasn't found. Initialize the new buffer as empty.
126 */
128
129 /* nodeBuffer->nodeBlocknum is the hash key and was filled in already */
130 nodeBuffer->blocksCount = 0;
131 nodeBuffer->pageBlocknum = InvalidBlockNumber;
132 nodeBuffer->pageBuffer = NULL;
133 nodeBuffer->queuedForEmptying = false;
134 nodeBuffer->isTemp = false;
135 nodeBuffer->level = level;
136
137 /*
138 * Add this buffer to the list of buffers on this level. Enlarge
139 * buffersOnLevels array if needed.
140 */
141 if (level >= gfbb->buffersOnLevelsLen)
142 {
143 int i;
144
145 gfbb->buffersOnLevels =
146 (List **) repalloc(gfbb->buffersOnLevels,
147 (level + 1) * sizeof(List *));
148
149 /* initialize the enlarged portion */
150 for (i = gfbb->buffersOnLevelsLen; i <= level; i++)
151 gfbb->buffersOnLevels[i] = NIL;
152 gfbb->buffersOnLevelsLen = level + 1;
153 }
154
155 /*
156 * Prepend the new buffer to the list of buffers on this level. It's
157 * not arbitrary that the new buffer is put to the beginning of the
158 * list: in the final emptying phase we loop through all buffers at
159 * each level, and flush them. If a page is split during the emptying,
160 * it's more efficient to flush the new split pages first, before
161 * moving on to pre-existing pages on the level. The buffers just
162 * created during the page split are likely still in cache, so
163 * flushing them immediately is more efficient than putting them to
164 * the end of the queue.
165 */
166 gfbb->buffersOnLevels[level] = lcons(nodeBuffer,
167 gfbb->buffersOnLevels[level]);
168
170 }
171
172 return nodeBuffer;
173}
#define InvalidBlockNumber
Definition block.h:33
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition dynahash.c:952
@ HASH_ENTER
Definition hsearch.h:114
List * lcons(void *datum, List *list)
Definition list.c:495
void * repalloc(void *pointer, Size size)
Definition mcxt.c:1632
#define NIL
Definition pg_list.h:68
List ** buffersOnLevels
MemoryContext context
GISTNodeBufferPage * pageBuffer
BlockNumber pageBlocknum

References GISTNodeBuffer::blocksCount, GISTBuildBuffers::buffersOnLevels, GISTBuildBuffers::buffersOnLevelsLen, GISTBuildBuffers::context, fb(), HASH_ENTER, hash_search(), i, InvalidBlockNumber, GISTNodeBuffer::isTemp, lcons(), GISTNodeBuffer::level, MemoryContextSwitchTo(), NIL, GISTBuildBuffers::nodeBuffersTab, GISTNodeBuffer::pageBlocknum, GISTNodeBuffer::pageBuffer, GISTNodeBuffer::queuedForEmptying, and repalloc().

Referenced by gistProcessItup(), and gistRelocateBuildBuffersOnSplit().

◆ gistgettuple()

bool gistgettuple ( IndexScanDesc  scan,
ScanDirection  dir 
)
extern

Definition at line 613 of file gistget.c.

614{
616
617 if (dir != ForwardScanDirection)
618 elog(ERROR, "GiST only supports forward scan direction");
619
620 if (!so->qual_ok)
621 return false;
622
623 if (so->firstCall)
624 {
625 /* Begin the scan by processing the root page */
627
629 if (scan->instrument)
630 scan->instrument->nsearches++;
631
632 so->firstCall = false;
633 so->curPageData = so->nPageData = 0;
634 scan->xs_hitup = NULL;
635 if (so->pageDataCxt)
636 MemoryContextReset(so->pageDataCxt);
637
639 memset(&fakeItem.data.parentlsn, 0, sizeof(GistNSN));
641 }
642
643 if (scan->numberOfOrderBys > 0)
644 {
645 /* Must fetch tuples in strict distance order */
646 return getNextNearest(scan);
647 }
648 else
649 {
650 /* Fetch tuples index-page-at-a-time */
651 for (;;)
652 {
653 if (so->curPageData < so->nPageData)
654 {
655 if (scan->kill_prior_tuple && so->curPageData > 0)
656 {
657
658 if (so->killedItems == NULL)
659 {
661 MemoryContextSwitchTo(so->giststate->scanCxt);
662
663 so->killedItems =
665 * sizeof(OffsetNumber));
666
668 }
669 if (so->numKilled < MaxIndexTuplesPerPage)
670 so->killedItems[so->numKilled++] =
671 so->pageData[so->curPageData - 1].offnum;
672 }
673 /* continuing to return tuples from a leaf page */
674 scan->xs_heaptid = so->pageData[so->curPageData].heapPtr;
675 scan->xs_recheck = so->pageData[so->curPageData].recheck;
676
677 /* in an index-only scan, also return the reconstructed tuple */
678 if (scan->xs_want_itup)
679 scan->xs_hitup = so->pageData[so->curPageData].recontup;
680
681 so->curPageData++;
682
683 return true;
684 }
685
686 /*
687 * Check the last returned tuple and add it to killedItems if
688 * necessary
689 */
690 if (scan->kill_prior_tuple
691 && so->curPageData > 0
692 && so->curPageData == so->nPageData)
693 {
694
695 if (so->killedItems == NULL)
696 {
698 MemoryContextSwitchTo(so->giststate->scanCxt);
699
700 so->killedItems =
702 * sizeof(OffsetNumber));
703
705 }
706 if (so->numKilled < MaxIndexTuplesPerPage)
707 so->killedItems[so->numKilled++] =
708 so->pageData[so->curPageData - 1].offnum;
709 }
710 /* find and process the next index page */
711 do
712 {
713 GISTSearchItem *item;
714
715 if ((so->curBlkno != InvalidBlockNumber) && (so->numKilled > 0))
716 gistkillitems(scan);
717
719
720 if (!item)
721 return false;
722
724
725 /* save current item BlockNumber for next gistkillitems() call */
726 so->curBlkno = item->blkno;
727
728 /*
729 * While scanning a leaf page, ItemPointers of matching heap
730 * tuples are stored in so->pageData. If there are any on
731 * this page, we fall out of the inner "do" and loop around to
732 * return them.
733 */
734 gistScanPage(scan, item, item->distances, NULL, NULL);
735
736 pfree(item);
737 } while (so->nPageData == 0);
738 }
739 }
740}
static bool getNextNearest(IndexScanDesc scan)
Definition gistget.c:561
static void gistkillitems(IndexScanDesc scan)
Definition gistget.c:39
#define MaxIndexTuplesPerPage
Definition itup.h:181
@ ForwardScanDirection
Definition sdir.h:28
BlockNumber blkno
bool kill_prior_tuple
Definition relscan.h:148
ItemPointerData xs_heaptid
Definition relscan.h:173

References GISTSearchItem::blkno, CHECK_FOR_INTERRUPTS, GISTSearchItem::distances, elog, ERROR, fb(), ForwardScanDirection, getNextGISTSearchItem(), getNextNearest(), GIST_ROOT_BLKNO, gistkillitems(), gistScanPage(), IndexScanDescData::indexRelation, IndexScanDescData::instrument, InvalidBlockNumber, IndexScanDescData::kill_prior_tuple, MaxIndexTuplesPerPage, MemoryContextReset(), MemoryContextSwitchTo(), IndexScanInstrumentation::nsearches, IndexScanDescData::numberOfOrderBys, IndexScanDescData::opaque, palloc(), pfree(), pgstat_count_index_scan, IndexScanDescData::xs_heaptid, IndexScanDescData::xs_hitup, IndexScanDescData::xs_recheck, and IndexScanDescData::xs_want_itup.

Referenced by gisthandler().

◆ GISTInitBuffer()

void GISTInitBuffer ( Buffer  b,
uint32  f 
)
extern

Definition at line 773 of file gistutil.c.

774{
775 Page page;
776
777 page = BufferGetPage(b);
778 gistinitpage(page, f);
779}
void gistinitpage(Page page, uint32 f)
Definition gistutil.c:757

References b, BufferGetPage(), and gistinitpage().

Referenced by gistbuild(), gistbuildempty(), gistplacetopage(), and gistRedoPageSplitRecord().

◆ gistInitBuildBuffers()

GISTBuildBuffers * gistInitBuildBuffers ( int  pagesPerBuffer,
int  levelStep,
int  maxLevel 
)
extern

Definition at line 44 of file gistbuildbuffers.c.

45{
46 GISTBuildBuffers *gfbb;
48
50 gfbb->pagesPerBuffer = pagesPerBuffer;
51 gfbb->levelStep = levelStep;
52
53 /*
54 * Create a temporary file to hold buffer pages that are swapped out of
55 * memory.
56 */
57 gfbb->pfile = BufFileCreateTemp(false);
58 gfbb->nFileBlocks = 0;
59
60 /* Initialize free page management. */
61 gfbb->nFreeBlocks = 0;
62 gfbb->freeBlocksLen = 32;
63 gfbb->freeBlocks = palloc_array(long, gfbb->freeBlocksLen);
64
65 /*
66 * Current memory context will be used for all in-memory data structures
67 * of buffers which are persistent during buffering build.
68 */
70
71 /*
72 * nodeBuffersTab hash is association between index blocks and it's
73 * buffers.
74 */
75 hashCtl.keysize = sizeof(BlockNumber);
76 hashCtl.entrysize = sizeof(GISTNodeBuffer);
78 gfbb->nodeBuffersTab = hash_create("gistbuildbuffers",
79 1024,
80 &hashCtl,
82
84
85 /*
86 * Per-level node buffers lists for final buffers emptying process. Node
87 * buffers are inserted here when they are created.
88 */
89 gfbb->buffersOnLevelsLen = 1;
91 gfbb->buffersOnLevels[0] = NIL;
92
93 /*
94 * Block numbers of node buffers which last pages are currently loaded
95 * into main memory.
96 */
97 gfbb->loadedBuffersLen = 32;
99 gfbb->loadedBuffersCount = 0;
100
101 gfbb->rootlevel = maxLevel;
102
103 return gfbb;
104}
BufFile * BufFileCreateTemp(bool interXact)
Definition buffile.c:193
HTAB * hash_create(const char *tabname, int64 nelem, const HASHCTL *info, int flags)
Definition dynahash.c:358
#define HASH_CONTEXT
Definition hsearch.h:102
#define HASH_ELEM
Definition hsearch.h:95
#define HASH_BLOBS
Definition hsearch.h:97
GISTNodeBuffer ** loadedBuffers
List * bufferEmptyingQueue

References GISTBuildBuffers::bufferEmptyingQueue, GISTBuildBuffers::buffersOnLevels, GISTBuildBuffers::buffersOnLevelsLen, BufFileCreateTemp(), GISTBuildBuffers::context, CurrentMemoryContext, fb(), GISTBuildBuffers::freeBlocks, GISTBuildBuffers::freeBlocksLen, HASH_BLOBS, HASH_CONTEXT, hash_create(), HASH_ELEM, GISTBuildBuffers::levelStep, GISTBuildBuffers::loadedBuffers, GISTBuildBuffers::loadedBuffersCount, GISTBuildBuffers::loadedBuffersLen, GISTBuildBuffers::nFileBlocks, GISTBuildBuffers::nFreeBlocks, NIL, GISTBuildBuffers::nodeBuffersTab, GISTBuildBuffers::pagesPerBuffer, palloc_array, palloc_object, GISTBuildBuffers::pfile, and GISTBuildBuffers::rootlevel.

Referenced by gistInitBuffering().

◆ gistinitpage()

void gistinitpage ( Page  page,
uint32  f 
)
extern

Definition at line 757 of file gistutil.c.

758{
759 GISTPageOpaque opaque;
760
761 PageInit(page, BLCKSZ, sizeof(GISTPageOpaqueData));
762
763 opaque = GistPageGetOpaque(page);
765 opaque->flags = f;
766 opaque->gist_page_id = GIST_PAGE_ID;
767}
void PageInit(Page page, Size pageSize, Size specialSize)
Definition bufpage.c:42
#define GIST_PAGE_ID
Definition gist.h:112
#define GistPageGetOpaque(page)
Definition gist.h:168
uint16 gist_page_id
Definition gist.h:83
BlockNumber rightlink
Definition gist.h:81
uint16 flags
Definition gist.h:82

References fb(), GISTPageOpaqueData::flags, GISTPageOpaqueData::gist_page_id, GIST_PAGE_ID, GistPageGetOpaque, InvalidBlockNumber, PageInit(), and GISTPageOpaqueData::rightlink.

Referenced by gist_indexsortbuild(), gist_indexsortbuild_levelstate_add(), gist_indexsortbuild_levelstate_flush(), and GISTInitBuffer().

◆ gistinsert()

bool gistinsert ( Relation  r,
Datum values,
bool isnull,
ItemPointer  ht_ctid,
Relation  heapRel,
IndexUniqueCheck  checkUnique,
bool  indexUnchanged,
struct IndexInfo indexInfo 
)
extern

Definition at line 166 of file gist.c.

171{
172 GISTSTATE *giststate = (GISTSTATE *) indexInfo->ii_AmCache;
173 IndexTuple itup;
175
176 /* Initialize GISTSTATE cache if first call in this statement */
177 if (giststate == NULL)
178 {
180 giststate = initGISTstate(r);
181 giststate->tempCxt = createTempGistContext();
182 indexInfo->ii_AmCache = giststate;
184 }
185
186 oldCxt = MemoryContextSwitchTo(giststate->tempCxt);
187
188 itup = gistFormTuple(giststate, r, values, isnull, true);
189 itup->t_tid = *ht_ctid;
190
191 gistdoinsert(r, itup, 0, giststate, heapRel, false);
192
193 /* cleanup */
195 MemoryContextReset(giststate->tempCxt);
196
197 return false;
198}
void gistdoinsert(Relation r, IndexTuple itup, Size freespace, GISTSTATE *giststate, Relation heapRel, bool is_build)
Definition gist.c:639
void * ii_AmCache
Definition execnodes.h:225
MemoryContext ii_Context
Definition execnodes.h:228

References createTempGistContext(), fb(), gistdoinsert(), gistFormTuple(), IndexInfo::ii_AmCache, IndexInfo::ii_Context, initGISTstate(), MemoryContextReset(), MemoryContextSwitchTo(), IndexTupleData::t_tid, GISTSTATE::tempCxt, and values.

Referenced by gisthandler().

◆ gistjoinvector()

IndexTuple * gistjoinvector ( IndexTuple itvec,
int len,
IndexTuple additvec,
int  addlen 
)
extern

Definition at line 114 of file gistutil.c.

115{
117 memmove(&itvec[*len], additvec, sizeof(IndexTuple) * addlen);
118 *len += addlen;
119 return itvec;
120}
#define repalloc_array(pointer, type, count)
Definition fe_memutils.h:78

References fb(), len, and repalloc_array.

Referenced by gist_indexsortbuild_levelstate_flush(), and gistplacetopage().

◆ gistKeyIsEQ()

bool gistKeyIsEQ ( GISTSTATE giststate,
int  attno,
Datum  a,
Datum  b 
)
extern

Definition at line 281 of file gistutil.c.

282{
283 bool result = false; /* silence compiler warning */
284
285 FunctionCall3Coll(&giststate->equalFn[attno],
286 giststate->supportCollation[attno],
287 a, b,
288 PointerGetDatum(&result));
289 return result;
290}
Datum FunctionCall3Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2, Datum arg3)
Definition fmgr.c:1172
FmgrInfo equalFn[INDEX_MAX_KEYS]

References a, b, GISTSTATE::equalFn, FunctionCall3Coll(), PointerGetDatum(), and GISTSTATE::supportCollation.

Referenced by gistgetadjusted(), and gistUserPicksplit().

◆ gistMakeUnionItVec()

void gistMakeUnionItVec ( GISTSTATE giststate,
IndexTuple itvec,
int  len,
Datum attr,
bool isnull 
)
extern

Definition at line 155 of file gistutil.c.

157{
158 int i;
160 int attrsize = 0; /* silence compiler warning */
161
162 evec = (GistEntryVector *) palloc((len + 2) * sizeof(GISTENTRY) + GEVHDRSZ);
163
164 for (i = 0; i < giststate->nonLeafTupdesc->natts; i++)
165 {
166 int j;
167
168 /* Collect non-null datums for this column */
169 evec->n = 0;
170 for (j = 0; j < len; j++)
171 {
172 Datum datum;
173 bool IsNull;
174
175 datum = index_getattr(itvec[j], i + 1, giststate->leafTupdesc,
176 &IsNull);
177 if (IsNull)
178 continue;
179
180 gistdentryinit(giststate, i,
181 evec->vector + evec->n,
182 datum,
183 NULL, NULL, (OffsetNumber) 0,
184 false, IsNull);
185 evec->n++;
186 }
187
188 /* If this column was all NULLs, the union is NULL */
189 if (evec->n == 0)
190 {
191 attr[i] = (Datum) 0;
192 isnull[i] = true;
193 }
194 else
195 {
196 if (evec->n == 1)
197 {
198 /* unionFn may expect at least two inputs */
199 evec->n = 2;
200 evec->vector[1] = evec->vector[0];
201 }
202
203 /* Make union and store in attr array */
204 attr[i] = FunctionCall2Coll(&giststate->unionFn[i],
205 giststate->supportCollation[i],
208
209 isnull[i] = false;
210 }
211 }
212}
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition fmgr.c:1150
#define GEVHDRSZ
Definition gist.h:240
TupleDesc nonLeafTupdesc
FmgrInfo unionFn[INDEX_MAX_KEYS]

References fb(), FunctionCall2Coll(), GEVHDRSZ, gistdentryinit(), i, index_getattr(), j, GISTSTATE::leafTupdesc, len, GistEntryVector::n, TupleDescData::natts, GISTSTATE::nonLeafTupdesc, palloc(), PointerGetDatum(), GISTSTATE::supportCollation, and GISTSTATE::unionFn.

Referenced by gistunion(), and gistunionsubkeyvec().

◆ gistMakeUnionKey()

void gistMakeUnionKey ( GISTSTATE giststate,
int  attno,
GISTENTRY entry1,
bool  isnull1,
GISTENTRY entry2,
bool  isnull2,
Datum dst,
bool dstisnull 
)
extern

Definition at line 233 of file gistutil.c.

237{
238 /* we need a GistEntryVector with room for exactly 2 elements */
239 union
240 {
242 char padding[2 * sizeof(GISTENTRY) + GEVHDRSZ];
243 } storage;
245 int dstsize = 0; /* silence compiler warning */
246
247 evec->n = 2;
248
249 if (isnull1 && isnull2)
250 {
251 *dstisnull = true;
252 *dst = (Datum) 0;
253 }
254 else
255 {
256 if (isnull1 == false && isnull2 == false)
257 {
258 evec->vector[0] = *entry1;
259 evec->vector[1] = *entry2;
260 }
261 else if (isnull1 == false)
262 {
263 evec->vector[0] = *entry1;
264 evec->vector[1] = *entry1;
265 }
266 else
267 {
268 evec->vector[0] = *entry2;
269 evec->vector[1] = *entry2;
270 }
271
272 *dstisnull = false;
273 *dst = FunctionCall2Coll(&giststate->unionFn[attno],
274 giststate->supportCollation[attno],
277 }
278}
#define storage

References fb(), FunctionCall2Coll(), GEVHDRSZ, GistEntryVector::n, PointerGetDatum(), storage, GISTSTATE::supportCollation, and GISTSTATE::unionFn.

Referenced by gistgetadjusted(), and supportSecondarySplit().

◆ gistNewBuffer()

Buffer gistNewBuffer ( Relation  r,
Relation  heaprel 
)
extern

Definition at line 824 of file gistutil.c.

825{
826 Buffer buffer;
827
828 /* First, try to get a page from FSM */
829 for (;;)
830 {
831 BlockNumber blkno = GetFreeIndexPage(r);
832
833 if (blkno == InvalidBlockNumber)
834 break; /* nothing left in FSM */
835
836 buffer = ReadBuffer(r, blkno);
837
838 /*
839 * We have to guard against the possibility that someone else already
840 * recycled this page; the buffer may be locked if so.
841 */
842 if (ConditionalLockBuffer(buffer))
843 {
844 Page page = BufferGetPage(buffer);
845
846 /*
847 * If the page was never initialized, it's OK to use.
848 */
849 if (PageIsNew(page))
850 return buffer;
851
852 gistcheckpage(r, buffer);
853
854 /*
855 * Otherwise, recycle it if deleted, and too old to have any
856 * processes interested in it.
857 */
858 if (gistPageRecyclable(page))
859 {
860 /*
861 * If we are generating WAL for Hot Standby then create a WAL
862 * record that will allow us to conflict with queries running
863 * on standby, in case they have snapshots older than the
864 * page's deleteXid.
865 */
867 gistXLogPageReuse(r, heaprel, blkno, GistPageGetDeleteXid(page));
868
869 return buffer;
870 }
871
872 LockBuffer(buffer, GIST_UNLOCK);
873 }
874
875 /* Can't use it, so release buffer and try again */
876 ReleaseBuffer(buffer);
877 }
878
879 /* Must extend the file */
882
883 return buffer;
884}
bool ConditionalLockBuffer(Buffer buffer)
Definition bufmgr.c:6474
static FullTransactionId GistPageGetDeleteXid(Page page)
Definition gist.h:216
bool gistPageRecyclable(Page page)
Definition gistutil.c:888
void gistXLogPageReuse(Relation rel, Relation heaprel, BlockNumber blkno, FullTransactionId deleteXid)
Definition gistxlog.c:592
BlockNumber GetFreeIndexPage(Relation rel)
Definition indexfsm.c:38
#define XLogStandbyInfoActive()
Definition xlog.h:125

References BMR_REL, BufferGetPage(), ConditionalLockBuffer(), EB_LOCK_FIRST, ExtendBufferedRel(), fb(), GetFreeIndexPage(), GIST_UNLOCK, gistcheckpage(), GistPageGetDeleteXid(), gistPageRecyclable(), gistXLogPageReuse(), InvalidBlockNumber, LockBuffer(), MAIN_FORKNUM, PageIsNew(), ReadBuffer(), RelationNeedsWAL, ReleaseBuffer(), and XLogStandbyInfoActive.

Referenced by gistbuild(), and gistplacetopage().

◆ gistnospace()

bool gistnospace ( Page  page,
IndexTuple itvec,
int  len,
OffsetNumber  todelete,
Size  freespace 
)
extern

Definition at line 59 of file gistutil.c.

60{
61 unsigned int size = freespace,
62 deleted = 0;
63 int i;
64
65 for (i = 0; i < len; i++)
66 size += IndexTupleSize(itvec[i]) + sizeof(ItemIdData);
67
69 {
71
72 deleted = IndexTupleSize(itup) + sizeof(ItemIdData);
73 }
74
75 return (PageGetFreeSpace(page) + deleted < size);
76}
Size PageGetFreeSpace(const PageData *page)
Definition bufpage.c:906

References fb(), i, IndexTupleSize(), InvalidOffsetNumber, len, PageGetFreeSpace(), PageGetItem(), and PageGetItemId().

Referenced by gistplacetopage().

◆ gistoptions()

bytea * gistoptions ( Datum  reloptions,
bool  validate 
)
extern

Definition at line 912 of file gistutil.c.

913{
914 static const relopt_parse_elt tab[] = {
916 {"buffering", RELOPT_TYPE_ENUM, offsetof(GiSTOptions, buffering_mode)}
917 };
918
919 return (bytea *) build_reloptions(reloptions, validate,
921 sizeof(GiSTOptions),
922 tab, lengthof(tab));
923}
#define lengthof(array)
Definition c.h:803
void * build_reloptions(Datum reloptions, bool validate, relopt_kind kind, Size relopt_struct_size, const relopt_parse_elt *relopt_elems, int num_relopt_elems)
@ RELOPT_KIND_GIST
Definition reloptions.h:48
@ RELOPT_TYPE_ENUM
Definition reloptions.h:35
@ RELOPT_TYPE_INT
Definition reloptions.h:33

References build_reloptions(), fb(), fillfactor, lengthof, RELOPT_KIND_GIST, RELOPT_TYPE_ENUM, RELOPT_TYPE_INT, and validate().

Referenced by gisthandler().

◆ gistPageRecyclable()

bool gistPageRecyclable ( Page  page)
extern

Definition at line 888 of file gistutil.c.

889{
890 if (PageIsNew(page))
891 return true;
892 if (GistPageIsDeleted(page))
893 {
894 /*
895 * The page was deleted, but when? If it was just deleted, a scan
896 * might have seen the downlink to it, and will read the page later.
897 * As long as that can happen, we must keep the deleted page around as
898 * a tombstone.
899 *
900 * For that check if the deletion XID could still be visible to
901 * anyone. If not, then no scan that's still in progress could have
902 * seen its downlink, and we can recycle it.
903 */
905
907 }
908 return false;
909}
bool GlobalVisCheckRemovableFullXid(Relation rel, FullTransactionId fxid)
Definition procarray.c:4265

References fb(), GistPageGetDeleteXid(), GistPageIsDeleted, GlobalVisCheckRemovableFullXid(), and PageIsNew().

Referenced by gistNewBuffer(), and gistvacuumpage().

◆ gistpenalty()

float gistpenalty ( GISTSTATE giststate,
int  attno,
GISTENTRY orig,
bool  isNullOrig,
GISTENTRY add,
bool  isNullAdd 
)
extern

Definition at line 724 of file gistutil.c.

727{
728 float penalty = 0.0;
729
730 if (giststate->penaltyFn[attno].fn_strict == false ||
731 (isNullOrig == false && isNullAdd == false))
732 {
733 FunctionCall3Coll(&giststate->penaltyFn[attno],
734 giststate->supportCollation[attno],
737 PointerGetDatum(&penalty));
738 /* disallow negative or NaN penalty */
739 if (isnan(penalty) || penalty < 0.0)
740 penalty = 0.0;
741 }
742 else if (isNullOrig && isNullAdd)
743 penalty = 0.0;
744 else
745 {
746 /* try to prevent mixing null and non-null values */
747 penalty = get_float4_infinity();
748 }
749
750 return penalty;
751}
static float4 get_float4_infinity(void)
Definition float.h:58
bool fn_strict
Definition fmgr.h:61
FmgrInfo penaltyFn[INDEX_MAX_KEYS]

References fb(), FmgrInfo::fn_strict, FunctionCall3Coll(), get_float4_infinity(), GISTSTATE::penaltyFn, PointerGetDatum(), and GISTSTATE::supportCollation.

Referenced by findDontCares(), gistchoose(), gistRelocateBuildBuffersOnSplit(), placeOne(), and supportSecondarySplit().

◆ gistplacetopage()

bool gistplacetopage ( Relation  rel,
Size  freespace,
GISTSTATE giststate,
Buffer  buffer,
IndexTuple itup,
int  ntup,
OffsetNumber  oldoffnum,
BlockNumber newblkno,
Buffer  leftchildbuf,
List **  splitinfo,
bool  markfollowright,
Relation  heapRel,
bool  is_build 
)
extern

Definition at line 231 of file gist.c.

240{
241 BlockNumber blkno = BufferGetBlockNumber(buffer);
242 Page page = BufferGetPage(buffer);
243 bool is_leaf = (GistPageIsLeaf(page)) ? true : false;
245 bool is_split;
246
247 /*
248 * Refuse to modify a page that's incompletely split. This should not
249 * happen because we finish any incomplete splits while we walk down the
250 * tree. However, it's remotely possible that another concurrent inserter
251 * splits a parent page, and errors out before completing the split. We
252 * will just throw an error in that case, and leave any split we had in
253 * progress unfinished too. The next insert that comes along will clean up
254 * the mess.
255 */
256 if (GistFollowRight(page))
257 elog(ERROR, "concurrent GiST page split was incomplete");
258
259 /* should never try to insert to a deleted page */
261
262 *splitinfo = NIL;
263
264 /*
265 * if isupdate, remove old key: This node's key has been modified, either
266 * because a child split occurred or because we needed to adjust our key
267 * for an insert in a child node. Therefore, remove the old version of
268 * this node's key.
269 *
270 * for WAL replay, in the non-split case we handle this by setting up a
271 * one-element todelete array; in the split case, it's handled implicitly
272 * because the tuple vector passed to gistSplit won't include this tuple.
273 */
274 is_split = gistnospace(page, itup, ntup, oldoffnum, freespace);
275
276 /*
277 * If leaf page is full, try at first to delete dead tuples. And then
278 * check again.
279 */
280 if (is_split && GistPageIsLeaf(page) && GistPageHasGarbage(page))
281 {
282 gistprunepage(rel, page, buffer, heapRel);
283 is_split = gistnospace(page, itup, ntup, oldoffnum, freespace);
284 }
285
286 if (is_split)
287 {
288 /* no space for insertion */
290 int tlen;
292 *ptr;
296 bool is_rootsplit;
297 int npage;
298
299 is_rootsplit = (blkno == GIST_ROOT_BLKNO);
300
301 /*
302 * Form index tuples vector to split. If we're replacing an old tuple,
303 * remove the old version from the vector.
304 */
305 itvec = gistextractpage(page, &tlen);
307 {
308 /* on inner page we should remove old tuple */
309 int pos = oldoffnum - FirstOffsetNumber;
310
311 tlen--;
312 if (pos != tlen)
313 memmove(itvec + pos, itvec + pos + 1, sizeof(IndexTuple) * (tlen - pos));
314 }
315 itvec = gistjoinvector(itvec, &tlen, itup, ntup);
316 dist = gistSplit(rel, page, itvec, tlen, giststate);
317
318 /*
319 * Check that split didn't produce too many pages.
320 */
321 npage = 0;
322 for (ptr = dist; ptr; ptr = ptr->next)
323 npage++;
324 /* in a root split, we'll add one more page to the list below */
325 if (is_rootsplit)
326 npage++;
327 if (npage > GIST_MAX_SPLIT_PAGES)
328 elog(ERROR, "GiST page split into too many halves (%d, maximum %d)",
329 npage, GIST_MAX_SPLIT_PAGES);
330
331 /*
332 * Set up pages to work with. Allocate new buffers for all but the
333 * leftmost page. The original page becomes the new leftmost page, and
334 * is just replaced with the new contents.
335 *
336 * For a root-split, allocate new buffers for all child pages, the
337 * original page is overwritten with new root page containing
338 * downlinks to the new child pages.
339 */
340 ptr = dist;
341 if (!is_rootsplit)
342 {
343 /* save old rightlink and NSN */
344 oldrlink = GistPageGetOpaque(page)->rightlink;
345 oldnsn = GistPageGetNSN(page);
346
347 dist->buffer = buffer;
348 dist->block.blkno = BufferGetBlockNumber(buffer);
350
351 /* clean all flags except F_LEAF */
352 GistPageGetOpaque(dist->page)->flags = (is_leaf) ? F_LEAF : 0;
353
354 ptr = ptr->next;
355 }
356 for (; ptr; ptr = ptr->next)
357 {
358 /* Allocate new page */
359 ptr->buffer = gistNewBuffer(rel, heapRel);
360 GISTInitBuffer(ptr->buffer, (is_leaf) ? F_LEAF : 0);
361 ptr->page = BufferGetPage(ptr->buffer);
362 ptr->block.blkno = BufferGetBlockNumber(ptr->buffer);
364 BufferGetBlockNumber(buffer),
365 BufferGetBlockNumber(ptr->buffer));
366 }
367
368 /*
369 * Now that we know which blocks the new pages go to, set up downlink
370 * tuples to point to them.
371 */
372 for (ptr = dist; ptr; ptr = ptr->next)
373 {
374 ItemPointerSetBlockNumber(&(ptr->itup->t_tid), ptr->block.blkno);
375 GistTupleSetValid(ptr->itup);
376 }
377
378 /*
379 * If this is a root split, we construct the new root page with the
380 * downlinks here directly, instead of requiring the caller to insert
381 * them. Add the new root page to the list along with the child pages.
382 */
383 if (is_rootsplit)
384 {
385 IndexTuple *downlinks;
386 int ndownlinks = 0;
387 int i;
388
389 rootpg.buffer = buffer;
391 GistPageGetOpaque(rootpg.page)->flags = 0;
392
393 /* Prepare a vector of all the downlinks */
394 for (ptr = dist; ptr; ptr = ptr->next)
395 ndownlinks++;
396 downlinks = palloc_array(IndexTuple, ndownlinks);
397 for (i = 0, ptr = dist; ptr; ptr = ptr->next)
398 downlinks[i++] = ptr->itup;
399
400 rootpg.block.blkno = GIST_ROOT_BLKNO;
401 rootpg.block.num = ndownlinks;
402 rootpg.list = gistfillitupvec(downlinks, ndownlinks,
403 &(rootpg.lenlist));
404 rootpg.itup = NULL;
405
406 rootpg.next = dist;
407 dist = &rootpg;
408 }
409 else
410 {
411 /* Prepare split-info to be returned to caller */
412 for (ptr = dist; ptr; ptr = ptr->next)
413 {
415
416 si->buf = ptr->buffer;
417 si->downlink = ptr->itup;
418 *splitinfo = lappend(*splitinfo, si);
419 }
420 }
421
422 /*
423 * Fill all pages. All the pages are new, ie. freshly allocated empty
424 * pages, or a temporary copy of the old page.
425 */
426 for (ptr = dist; ptr; ptr = ptr->next)
427 {
428 char *data = (char *) (ptr->list);
429
430 for (int i = 0; i < ptr->block.num; i++)
431 {
433
434 if (PageAddItem(ptr->page, data, IndexTupleSize(thistup), i + FirstOffsetNumber, false, false) == InvalidOffsetNumber)
435 elog(ERROR, "failed to add item to index page in \"%s\"", RelationGetRelationName(rel));
436
437 /*
438 * If this is the first inserted/updated tuple, let the caller
439 * know which page it landed on.
440 */
441 if (newblkno && ItemPointerEquals(&thistup->t_tid, &(*itup)->t_tid))
442 *newblkno = ptr->block.blkno;
443
445 }
446
447 /* Set up rightlinks */
448 if (ptr->next && ptr->block.blkno != GIST_ROOT_BLKNO)
449 GistPageGetOpaque(ptr->page)->rightlink =
450 ptr->next->block.blkno;
451 else
452 GistPageGetOpaque(ptr->page)->rightlink = oldrlink;
453
454 /*
455 * Mark the all but the right-most page with the follow-right
456 * flag. It will be cleared as soon as the downlink is inserted
457 * into the parent, but this ensures that if we error out before
458 * that, the index is still consistent. (in buffering build mode,
459 * any error will abort the index build anyway, so this is not
460 * needed.)
461 */
462 if (ptr->next && !is_rootsplit && markfollowright)
463 GistMarkFollowRight(ptr->page);
464 else
465 GistClearFollowRight(ptr->page);
466
467 /*
468 * Copy the NSN of the original page to all pages. The
469 * F_FOLLOW_RIGHT flags ensure that scans will follow the
470 * rightlinks until the downlinks are inserted.
471 */
472 GistPageSetNSN(ptr->page, oldnsn);
473 }
474
475 /*
476 * gistXLogSplit() needs to WAL log a lot of pages, prepare WAL
477 * insertion for that. NB: The number of pages and data segments
478 * specified here must match the calculations in gistXLogSplit()!
479 */
480 if (!is_build && RelationNeedsWAL(rel))
481 XLogEnsureRecordSpace(npage, 1 + npage * 2);
482
484
485 /*
486 * Must mark buffers dirty before XLogInsert, even though we'll still
487 * be changing their opaque fields below.
488 */
489 for (ptr = dist; ptr; ptr = ptr->next)
490 MarkBufferDirty(ptr->buffer);
493
494 /*
495 * The first page in the chain was a temporary working copy meant to
496 * replace the old page. Copy it over the old page.
497 */
499 dist->page = BufferGetPage(dist->buffer);
500
501 /*
502 * Write the WAL record.
503 *
504 * If we're building a new index, however, we don't WAL-log changes
505 * yet. The LSN-NSN interlock between parent and child requires that
506 * LSNs never move backwards, so set the LSNs to a value that's
507 * smaller than any real or fake unlogged LSN that might be generated
508 * later. (There can't be any concurrent scans during index build, so
509 * we don't need to be able to detect concurrent splits yet.)
510 */
511 if (is_build)
513 else
514 {
515 if (RelationNeedsWAL(rel))
516 recptr = gistXLogSplit(is_leaf,
518 markfollowright);
519 else
520 recptr = gistGetFakeLSN(rel);
521 }
522
523 for (ptr = dist; ptr; ptr = ptr->next)
524 PageSetLSN(ptr->page, recptr);
525
526 /*
527 * Return the new child buffers to the caller.
528 *
529 * If this was a root split, we've already inserted the downlink
530 * pointers, in the form of a new root page. Therefore we can release
531 * all the new buffers, and keep just the root page locked.
532 */
533 if (is_rootsplit)
534 {
535 for (ptr = dist->next; ptr; ptr = ptr->next)
536 UnlockReleaseBuffer(ptr->buffer);
537 }
538 }
539 else
540 {
541 /*
542 * Enough space. We always get here if ntup==0.
543 */
545
546 /*
547 * Delete old tuple if any, then insert new tuple(s) if any. If
548 * possible, use the fast path of PageIndexTupleOverwrite.
549 */
551 {
552 if (ntup == 1)
553 {
554 /* One-for-one replacement, so use PageIndexTupleOverwrite */
555 if (!PageIndexTupleOverwrite(page, oldoffnum, *itup, IndexTupleSize(*itup)))
556 elog(ERROR, "failed to add item to index page in \"%s\"",
558 }
559 else
560 {
561 /* Delete old, then append new tuple(s) to page */
564 }
565 }
566 else
567 {
568 /* Just append new tuples at the end of the page */
570 }
571
572 MarkBufferDirty(buffer);
573
576
577 if (is_build)
579 else
580 {
581 if (RelationNeedsWAL(rel))
582 {
584 deloffs[1];
585
587 {
588 deloffs[0] = oldoffnum;
589 ndeloffs = 1;
590 }
591
592 recptr = gistXLogUpdate(buffer,
593 deloffs, ndeloffs, itup, ntup,
595 }
596 else
597 recptr = gistGetFakeLSN(rel);
598 }
599 PageSetLSN(page, recptr);
600
601 if (newblkno)
602 *newblkno = blkno;
603 }
604
605 /*
606 * If we inserted the downlink for a child page, set NSN and clear
607 * F_FOLLOW_RIGHT flag on the left child, so that concurrent scans know to
608 * follow the rightlink if and only if they looked at the parent page
609 * before we inserted the downlink.
610 *
611 * Note that we do this *after* writing the WAL record. That means that
612 * the possible full page image in the WAL record does not include these
613 * changes, and they must be replayed even if the page is restored from
614 * the full page image. There's a chicken-and-egg problem: if we updated
615 * the child pages first, we wouldn't know the recptr of the WAL record
616 * we're about to write.
617 */
619 {
621
624
626 }
627
629
630 return is_split;
631}
static bool BufferIsValid(Buffer bufnum)
Definition bufmgr.h:417
void PageRestoreTempPage(Page tempPage, Page oldPage)
Definition bufpage.c:423
bool PageIndexTupleOverwrite(Page page, OffsetNumber offnum, const void *newtup, Size newsize)
Definition bufpage.c:1404
void PageIndexTupleDelete(Page page, OffsetNumber offnum)
Definition bufpage.c:1051
Page PageGetTempPageCopySpecial(const PageData *page)
Definition bufpage.c:401
SplitPageLayout * gistSplit(Relation r, Page page, IndexTuple *itup, int len, GISTSTATE *giststate)
Definition gist.c:1450
static void gistprunepage(Relation rel, Page page, Buffer buffer, Relation heapRel)
Definition gist.c:1675
#define GistMarkFollowRight(page)
Definition gist.h:184
#define GistClearFollowRight(page)
Definition gist.h:185
#define GistPageSetNSN(page, val)
Definition gist.h:188
#define GistPageHasGarbage(page)
Definition gist.h:179
#define GIST_MAX_SPLIT_PAGES
#define GistTupleSetValid(itup)
bool gistnospace(Page page, IndexTuple *itvec, int len, OffsetNumber todelete, Size freespace)
Definition gistutil.c:59
void gistfillbuffer(Page page, IndexTuple *itup, int len, OffsetNumber off)
Definition gistutil.c:34
IndexTuple * gistextractpage(Page page, int *len)
Definition gistutil.c:95
XLogRecPtr gistGetFakeLSN(Relation rel)
Definition gistutil.c:1016
IndexTuple * gistjoinvector(IndexTuple *itvec, int *len, IndexTuple *additvec, int addlen)
Definition gistutil.c:114
IndexTupleData * gistfillitupvec(IndexTuple *vec, int veclen, int *memlen)
Definition gistutil.c:127
XLogRecPtr gistXLogSplit(bool page_is_leaf, SplitPageLayout *dist, BlockNumber origrlink, GistNSN orignsn, Buffer leftchildbuf, bool markfollowright)
Definition gistxlog.c:493
XLogRecPtr gistXLogUpdate(Buffer buffer, OffsetNumber *todelete, int ntodelete, IndexTuple *itup, int ituplen, Buffer leftchildbuf)
Definition gistxlog.c:627
#define false
bool ItemPointerEquals(const ItemPointerData *pointer1, const ItemPointerData *pointer2)
Definition itemptr.c:35
static void ItemPointerSetBlockNumber(ItemPointerData *pointer, BlockNumber blockNumber)
Definition itemptr.h:147
List * lappend(List *list, void *datum)
Definition list.c:339
#define OffsetNumberIsValid(offsetNumber)
Definition off.h:39
const void * data
void PredicateLockPageSplit(Relation relation, BlockNumber oldblkno, BlockNumber newblkno)
Definition predicate.c:3142
void XLogEnsureRecordSpace(int max_block_id, int ndatas)
Definition xloginsert.c:178

References Assert, BufferGetBlockNumber(), BufferGetPage(), BufferIsValid(), data, elog, END_CRIT_SECTION, ERROR, F_LEAF, fb(), FirstOffsetNumber, GIST_MAX_SPLIT_PAGES, GIST_ROOT_BLKNO, GistBuildLSN, GistClearFollowRight, gistextractpage(), gistfillbuffer(), gistfillitupvec(), GistFollowRight, gistGetFakeLSN(), GISTInitBuffer(), gistjoinvector(), GistMarkFollowRight, gistNewBuffer(), gistnospace(), GistPageGetNSN, GistPageGetOpaque, GistPageHasGarbage, GistPageIsDeleted, GistPageIsLeaf, GistPageSetNSN, gistprunepage(), gistSplit(), GistTupleSetValid, gistXLogSplit(), gistXLogUpdate(), i, IndexTupleSize(), InvalidBlockNumber, InvalidOffsetNumber, InvalidXLogRecPtr, ItemPointerEquals(), ItemPointerSetBlockNumber(), lappend(), MarkBufferDirty(), NIL, OffsetNumberIsValid, PageAddItem, PageGetTempPageCopySpecial(), PageIndexTupleDelete(), PageIndexTupleOverwrite(), PageRestoreTempPage(), PageSetLSN(), palloc_array, palloc_object, PredicateLockPageSplit(), RelationGetRelationName, RelationNeedsWAL, START_CRIT_SECTION, UnlockReleaseBuffer(), and XLogEnsureRecordSpace().

Referenced by gistbufferinginserttuples(), and gistinserttuples().

◆ gistPopItupFromNodeBuffer()

bool gistPopItupFromNodeBuffer ( GISTBuildBuffers gfbb,
GISTNodeBuffer nodeBuffer,
IndexTuple itup 
)
extern

Definition at line 404 of file gistbuildbuffers.c.

406{
407 /*
408 * If node buffer is empty then return false.
409 */
410 if (nodeBuffer->blocksCount <= 0)
411 return false;
412
413 /* Load last page of node buffer if needed */
414 if (!nodeBuffer->pageBuffer)
415 gistLoadNodeBuffer(gfbb, nodeBuffer);
416
417 /*
418 * Get index tuple from last non-empty page.
419 */
420 gistGetItupFromPage(nodeBuffer->pageBuffer, itup);
421
422 /*
423 * If we just removed the last tuple from the page, fetch previous page on
424 * this node buffer (if any).
425 */
426 if (PAGE_IS_EMPTY(nodeBuffer->pageBuffer))
427 {
428 BlockNumber prevblkno;
429
430 /*
431 * blocksCount includes the page in pageBuffer, so decrease it now.
432 */
433 nodeBuffer->blocksCount--;
434
435 /*
436 * If there's more pages, fetch previous one.
437 */
438 prevblkno = nodeBuffer->pageBuffer->prev;
439 if (prevblkno != InvalidBlockNumber)
440 {
441 /* There is a previous page. Fetch it. */
442 Assert(nodeBuffer->blocksCount > 0);
443 ReadTempFileBlock(gfbb->pfile, prevblkno, nodeBuffer->pageBuffer);
444
445 /*
446 * Now that we've read the block in memory, we can release its
447 * on-disk block for reuse.
448 */
449 gistBuffersReleaseBlock(gfbb, prevblkno);
450 }
451 else
452 {
453 /* No more pages. Free memory. */
454 Assert(nodeBuffer->blocksCount == 0);
455 pfree(nodeBuffer->pageBuffer);
456 nodeBuffer->pageBuffer = NULL;
457 }
458 }
459 return true;
460}
#define PAGE_IS_EMPTY(nbp)
static void gistBuffersReleaseBlock(GISTBuildBuffers *gfbb, long blocknum)
static void gistLoadNodeBuffer(GISTBuildBuffers *gfbb, GISTNodeBuffer *nodeBuffer)
static void ReadTempFileBlock(BufFile *file, long blknum, void *ptr)
static void gistGetItupFromPage(GISTNodeBufferPage *pageBuffer, IndexTuple *itup)

References Assert, GISTNodeBuffer::blocksCount, fb(), gistBuffersReleaseBlock(), gistGetItupFromPage(), gistLoadNodeBuffer(), InvalidBlockNumber, PAGE_IS_EMPTY, GISTNodeBuffer::pageBuffer, GISTBuildBuffers::pfile, pfree(), GISTNodeBufferPage::prev, and ReadTempFileBlock().

Referenced by gistProcessEmptyingQueue(), and gistRelocateBuildBuffersOnSplit().

◆ gistproperty()

bool gistproperty ( Oid  index_oid,
int  attno,
IndexAMProperty  prop,
const char propname,
bool res,
bool isnull 
)
extern

Definition at line 933 of file gistutil.c.

936{
937 Oid opclass,
938 opfamily,
939 opcintype;
940 int16 procno;
941
942 /* Only answer column-level inquiries */
943 if (attno == 0)
944 return false;
945
946 /*
947 * Currently, GiST distance-ordered scans require that there be a distance
948 * function in the opclass with the default types (i.e. the one loaded
949 * into the relcache entry, see initGISTstate). So we assume that if such
950 * a function exists, then there's a reason for it (rather than grubbing
951 * through all the opfamily's operators to find an ordered one).
952 *
953 * Essentially the same code can test whether we support returning the
954 * column data, since that's true if the opclass provides a fetch proc.
955 */
956
957 switch (prop)
958 {
960 procno = GIST_DISTANCE_PROC;
961 break;
963 procno = GIST_FETCH_PROC;
964 break;
965 default:
966 return false;
967 }
968
969 /* First we need to know the column's opclass. */
970 opclass = get_index_column_opclass(index_oid, attno);
971 if (!OidIsValid(opclass))
972 {
973 *isnull = true;
974 return true;
975 }
976
977 /* Now look up the opclass family and input datatype. */
978 if (!get_opclass_opfamily_and_input_type(opclass, &opfamily, &opcintype))
979 {
980 *isnull = true;
981 return true;
982 }
983
984 /* And now we can check whether the function is provided. */
985
987 ObjectIdGetDatum(opfamily),
988 ObjectIdGetDatum(opcintype),
989 ObjectIdGetDatum(opcintype),
990 Int16GetDatum(procno));
991
992 /*
993 * Special case: even without a fetch function, AMPROP_RETURNABLE is true
994 * if the opclass has no compress function.
995 */
996 if (prop == AMPROP_RETURNABLE && !*res)
997 {
999 ObjectIdGetDatum(opfamily),
1000 ObjectIdGetDatum(opcintype),
1001 ObjectIdGetDatum(opcintype),
1003 }
1004
1005 *isnull = false;
1006
1007 return true;
1008}
@ AMPROP_DISTANCE_ORDERABLE
Definition amapi.h:46
@ AMPROP_RETURNABLE
Definition amapi.h:47
int16_t int16
Definition c.h:541
bool get_opclass_opfamily_and_input_type(Oid opclass, Oid *opfamily, Oid *opcintype)
Definition lsyscache.c:1337
Oid get_index_column_opclass(Oid index_oid, int attno)
Definition lsyscache.c:3662
static Datum Int16GetDatum(int16 X)
Definition postgres.h:182
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:262
#define SearchSysCacheExists4(cacheId, key1, key2, key3, key4)
Definition syscache.h:106

References AMPROP_DISTANCE_ORDERABLE, AMPROP_RETURNABLE, fb(), get_index_column_opclass(), get_opclass_opfamily_and_input_type(), GIST_COMPRESS_PROC, GIST_DISTANCE_PROC, GIST_FETCH_PROC, Int16GetDatum(), ObjectIdGetDatum(), OidIsValid, and SearchSysCacheExists4.

Referenced by gisthandler().

◆ gistPushItupToNodeBuffer()

void gistPushItupToNodeBuffer ( GISTBuildBuffers gfbb,
GISTNodeBuffer nodeBuffer,
IndexTuple  itup 
)
extern

Definition at line 334 of file gistbuildbuffers.c.

336{
337 /*
338 * Most part of memory operations will be in buffering build persistent
339 * context. So, let's switch to it.
340 */
342
343 /*
344 * If the buffer is currently empty, create the first page.
345 */
346 if (nodeBuffer->blocksCount == 0)
347 {
348 nodeBuffer->pageBuffer = gistAllocateNewPageBuffer(gfbb);
349 nodeBuffer->blocksCount = 1;
350 gistAddLoadedBuffer(gfbb, nodeBuffer);
351 }
352
353 /* Load last page of node buffer if it wasn't in memory already */
354 if (!nodeBuffer->pageBuffer)
355 gistLoadNodeBuffer(gfbb, nodeBuffer);
356
357 /*
358 * Check if there is enough space on the last page for the tuple.
359 */
360 if (PAGE_NO_SPACE(nodeBuffer->pageBuffer, itup))
361 {
362 /*
363 * Nope. Swap previous block to disk and allocate a new one.
364 */
365 BlockNumber blkno;
366
367 /* Write filled page to the disk */
368 blkno = gistBuffersGetFreeBlock(gfbb);
369 WriteTempFileBlock(gfbb->pfile, blkno, nodeBuffer->pageBuffer);
370
371 /*
372 * Reset the in-memory page as empty, and link the previous block to
373 * the new page by storing its block number in the prev-link.
374 */
375 PAGE_FREE_SPACE(nodeBuffer->pageBuffer) =
377 nodeBuffer->pageBuffer->prev = blkno;
378
379 /* We've just added one more page */
380 nodeBuffer->blocksCount++;
381 }
382
383 gistPlaceItupToPage(nodeBuffer->pageBuffer, itup);
384
385 /*
386 * If the buffer just overflowed, add it to the emptying queue.
387 */
388 if (BUFFER_HALF_FILLED(nodeBuffer, gfbb) && !nodeBuffer->queuedForEmptying)
389 {
390 gfbb->bufferEmptyingQueue = lcons(nodeBuffer,
391 gfbb->bufferEmptyingQueue);
392 nodeBuffer->queuedForEmptying = true;
393 }
394
395 /* Restore memory context */
397}
#define BUFFER_HALF_FILLED(nodeBuffer, gfbb)
#define PAGE_NO_SPACE(nbp, itup)
static void WriteTempFileBlock(BufFile *file, long blknum, const void *ptr)
static void gistAddLoadedBuffer(GISTBuildBuffers *gfbb, GISTNodeBuffer *nodeBuffer)
static void gistPlaceItupToPage(GISTNodeBufferPage *pageBuffer, IndexTuple itup)
static GISTNodeBufferPage * gistAllocateNewPageBuffer(GISTBuildBuffers *gfbb)
static long gistBuffersGetFreeBlock(GISTBuildBuffers *gfbb)

References GISTNodeBuffer::blocksCount, BUFFER_HALF_FILLED, GISTBuildBuffers::bufferEmptyingQueue, GISTBuildBuffers::context, fb(), gistAddLoadedBuffer(), gistAllocateNewPageBuffer(), gistBuffersGetFreeBlock(), gistLoadNodeBuffer(), gistPlaceItupToPage(), lcons(), MAXALIGN, MemoryContextSwitchTo(), PAGE_FREE_SPACE, PAGE_NO_SPACE, GISTNodeBuffer::pageBuffer, GISTBuildBuffers::pfile, GISTNodeBufferPage::prev, GISTNodeBuffer::queuedForEmptying, and WriteTempFileBlock().

Referenced by gistProcessItup(), and gistRelocateBuildBuffersOnSplit().

◆ gistRelocateBuildBuffersOnSplit()

void gistRelocateBuildBuffersOnSplit ( GISTBuildBuffers gfbb,
GISTSTATE giststate,
Relation  r,
int  level,
Buffer  buffer,
List splitinfo 
)
extern

Definition at line 531 of file gistbuildbuffers.c.

534{
536 bool found;
537 GISTNodeBuffer *nodeBuffer;
538 BlockNumber blocknum;
539 IndexTuple itup;
540 int splitPagesCount = 0;
542 bool isnull[INDEX_MAX_KEYS];
544 ListCell *lc;
545
546 /* If the split page doesn't have buffers, we have nothing to do. */
547 if (!LEVEL_HAS_BUFFERS(level, gfbb))
548 return;
549
550 /*
551 * Get the node buffer of the split page.
552 */
553 blocknum = BufferGetBlockNumber(buffer);
554 nodeBuffer = hash_search(gfbb->nodeBuffersTab, &blocknum,
555 HASH_FIND, &found);
556 if (!found)
557 {
558 /* The page has no buffer, so we have nothing to do. */
559 return;
560 }
561
562 /*
563 * Make a copy of the old buffer, as we're going reuse it as the buffer
564 * for the new left page, which is on the same block as the old page.
565 * That's not true for the root page, but that's fine because we never
566 * have a buffer on the root page anyway. The original algorithm as
567 * described by Arge et al did, but it's of no use, as you might as well
568 * read the tuples straight from the heap instead of the root buffer.
569 */
570 Assert(blocknum != GIST_ROOT_BLKNO);
571 memcpy(&oldBuf, nodeBuffer, sizeof(GISTNodeBuffer));
572 oldBuf.isTemp = true;
573
574 /* Reset the old buffer, used for the new left page from now on */
575 nodeBuffer->blocksCount = 0;
576 nodeBuffer->pageBuffer = NULL;
577 nodeBuffer->pageBlocknum = InvalidBlockNumber;
578
579 /*
580 * Allocate memory for information about relocation buffers.
581 */
582 splitPagesCount = list_length(splitinfo);
584
585 /*
586 * Fill relocation buffers information for node buffers of pages produced
587 * by split.
588 */
589 foreach(lc, splitinfo)
590 {
594
595 /* Decompress parent index tuple of node buffer page. */
596 gistDeCompressAtt(giststate, r,
597 si->downlink, NULL, (OffsetNumber) 0,
599 relocationBuffersInfos[i].isnull);
600
601 /*
602 * Create a node buffer for the page. The leftmost half is on the same
603 * block as the old page before split, so for the leftmost half this
604 * will return the original buffer. The tuples on the original buffer
605 * were relinked to the temporary buffer, so the original one is now
606 * empty.
607 */
608 newNodeBuffer = gistGetNodeBuffer(gfbb, giststate, BufferGetBlockNumber(si->buf), level);
609
611 relocationBuffersInfos[i].splitinfo = si;
612 }
613
614 /*
615 * Loop through all index tuples in the buffer of the page being split,
616 * moving them to buffers for the new pages. We try to move each tuple to
617 * the page that will result in the lowest penalty for the leading column
618 * or, in the case of a tie, the lowest penalty for the earliest column
619 * that is not tied.
620 *
621 * The page searching logic is very similar to gistchoose().
622 */
623 while (gistPopItupFromNodeBuffer(gfbb, &oldBuf, &itup))
624 {
626 int i,
627 which;
630
631 gistDeCompressAtt(giststate, r,
632 itup, NULL, (OffsetNumber) 0, entry, isnull);
633
634 /* default to using first page (shouldn't matter) */
635 which = 0;
636
637 /*
638 * best_penalty[j] is the best penalty we have seen so far for column
639 * j, or -1 when we haven't yet examined column j. Array entries to
640 * the right of the first -1 are undefined.
641 */
642 best_penalty[0] = -1;
643
644 /*
645 * Loop over possible target pages, looking for one to move this tuple
646 * to.
647 */
648 for (i = 0; i < splitPagesCount; i++)
649 {
651 bool zero_penalty;
652 int j;
653
654 zero_penalty = true;
655
656 /* Loop over index attributes. */
657 for (j = 0; j < IndexRelationGetNumberOfKeyAttributes(r); j++)
658 {
659 float usize;
660
661 /* Compute penalty for this column. */
662 usize = gistpenalty(giststate, j,
663 &splitPageInfo->entry[j],
664 splitPageInfo->isnull[j],
665 &entry[j], isnull[j]);
666 if (usize > 0)
667 zero_penalty = false;
668
669 if (best_penalty[j] < 0 || usize < best_penalty[j])
670 {
671 /*
672 * New best penalty for column. Tentatively select this
673 * page as the target, and record the best penalty. Then
674 * reset the next column's penalty to "unknown" (and
675 * indirectly, the same for all the ones to its right).
676 * This will force us to adopt this page's penalty values
677 * as the best for all the remaining columns during
678 * subsequent loop iterations.
679 */
680 which = i;
682
684 best_penalty[j + 1] = -1;
685 }
686 else if (best_penalty[j] == usize)
687 {
688 /*
689 * The current page is exactly as good for this column as
690 * the best page seen so far. The next iteration of this
691 * loop will compare the next column.
692 */
693 }
694 else
695 {
696 /*
697 * The current page is worse for this column than the best
698 * page seen so far. Skip the remaining columns and move
699 * on to the next page, if any.
700 */
701 zero_penalty = false; /* so outer loop won't exit */
702 break;
703 }
704 }
705
706 /*
707 * If we find a page with zero penalty for all columns, there's no
708 * need to examine remaining pages; just break out of the loop and
709 * return it.
710 */
711 if (zero_penalty)
712 break;
713 }
714
715 /* OK, "which" is the page index to push the tuple to */
717
718 /* Push item to selected node buffer */
719 gistPushItupToNodeBuffer(gfbb, targetBufferInfo->nodeBuffer, itup);
720
721 /* Adjust the downlink for this page, if needed. */
722 newtup = gistgetadjusted(r, targetBufferInfo->splitinfo->downlink,
723 itup, giststate);
724 if (newtup)
725 {
726 gistDeCompressAtt(giststate, r,
728 targetBufferInfo->entry,
729 targetBufferInfo->isnull);
730
731 targetBufferInfo->splitinfo->downlink = newtup;
732 }
733 }
734
736}
#define LEVEL_HAS_BUFFERS(nlevel, gfbb)
void gistPushItupToNodeBuffer(GISTBuildBuffers *gfbb, GISTNodeBuffer *nodeBuffer, IndexTuple itup)
bool gistPopItupFromNodeBuffer(GISTBuildBuffers *gfbb, GISTNodeBuffer *nodeBuffer, IndexTuple *itup)
GISTNodeBuffer * gistGetNodeBuffer(GISTBuildBuffers *gfbb, GISTSTATE *giststate, BlockNumber nodeBlocknum, int level)
@ HASH_FIND
Definition hsearch.h:113
static int list_length(const List *l)
Definition pg_list.h:152
#define foreach_current_index(var_or_cell)
Definition pg_list.h:403

References Assert, GISTNodeBuffer::blocksCount, BufferGetBlockNumber(), fb(), foreach_current_index, GIST_ROOT_BLKNO, gistDeCompressAtt(), gistgetadjusted(), gistGetNodeBuffer(), gistpenalty(), gistPopItupFromNodeBuffer(), gistPushItupToNodeBuffer(), HASH_FIND, hash_search(), i, INDEX_MAX_KEYS, IndexRelationGetNumberOfKeyAttributes, InvalidBlockNumber, j, LEVEL_HAS_BUFFERS, lfirst, list_length(), GISTBuildBuffers::nodeBuffersTab, GISTNodeBuffer::pageBlocknum, GISTNodeBuffer::pageBuffer, palloc_array, and pfree().

Referenced by gistbufferinginserttuples().

◆ gistSplit()

SplitPageLayout * gistSplit ( Relation  r,
Page  page,
IndexTuple itup,
int  len,
GISTSTATE giststate 
)
extern

Definition at line 1450 of file gist.c.

1455{
1457 *rvectup;
1459 int i;
1460 SplitPageLayout *res = NULL;
1461
1462 /* this should never recurse very deeply, but better safe than sorry */
1464
1465 /* there's no point in splitting an empty page */
1466 Assert(len > 0);
1467
1468 /*
1469 * If a single tuple doesn't fit on a page, no amount of splitting will
1470 * help.
1471 */
1472 if (len == 1)
1473 ereport(ERROR,
1475 errmsg("index row size %zu exceeds maximum %zu for index \"%s\"",
1476 IndexTupleSize(itup[0]), GiSTPageSize,
1478
1479 memset(v.spl_lisnull, true,
1480 sizeof(bool) * giststate->nonLeafTupdesc->natts);
1481 memset(v.spl_risnull, true,
1482 sizeof(bool) * giststate->nonLeafTupdesc->natts);
1483 gistSplitByKey(r, page, itup, len, giststate, &v, 0);
1484
1485 /* form left and right vector */
1488
1489 for (i = 0; i < v.splitVector.spl_nleft; i++)
1490 lvectup[i] = itup[v.splitVector.spl_left[i] - 1];
1491
1492 for (i = 0; i < v.splitVector.spl_nright; i++)
1493 rvectup[i] = itup[v.splitVector.spl_right[i] - 1];
1494
1495 /* finalize splitting (may need another split) */
1497 {
1498 res = gistSplit(r, page, rvectup, v.splitVector.spl_nright, giststate);
1499 }
1500 else
1501 {
1502 ROTATEDIST(res);
1505 res->itup = gistFormTuple(giststate, r, v.spl_rattr, v.spl_risnull, false);
1506 }
1507
1509 {
1511 *subres;
1512
1513 resptr = subres = gistSplit(r, page, lvectup, v.splitVector.spl_nleft, giststate);
1514
1515 /* install on list's tail */
1516 while (resptr->next)
1517 resptr = resptr->next;
1518
1519 resptr->next = res;
1520 res = subres;
1521 }
1522 else
1523 {
1524 ROTATEDIST(res);
1525 res->block.num = v.splitVector.spl_nleft;
1527 res->itup = gistFormTuple(giststate, r, v.spl_lattr, v.spl_lisnull, false);
1528 }
1529
1530 return res;
1531}
#define ROTATEDIST(d)
Definition gist.c:45
void gistSplitByKey(Relation r, Page page, IndexTuple *itup, int len, GISTSTATE *giststate, GistSplitVector *v, int attno)
Definition gistsplit.c:623
bool gistfitpage(IndexTuple *itvec, int len)
Definition gistutil.c:79
void check_stack_depth(void)
Definition stack_depth.c:95
int spl_nleft
Definition gist.h:144
OffsetNumber * spl_right
Definition gist.h:148
int spl_nright
Definition gist.h:149
OffsetNumber * spl_left
Definition gist.h:143
GIST_SPLITVEC splitVector
Datum spl_lattr[INDEX_MAX_KEYS]
bool spl_lisnull[INDEX_MAX_KEYS]
Datum spl_rattr[INDEX_MAX_KEYS]
bool spl_risnull[INDEX_MAX_KEYS]
gistxlogPage block
IndexTuple itup
IndexTupleData * list

References Assert, SplitPageLayout::block, check_stack_depth(), ereport, errcode(), errmsg(), ERROR, fb(), gistfillitupvec(), gistfitpage(), gistFormTuple(), GiSTPageSize, gistSplit(), gistSplitByKey(), i, IndexTupleSize(), SplitPageLayout::itup, len, SplitPageLayout::lenlist, SplitPageLayout::list, TupleDescData::natts, GISTSTATE::nonLeafTupdesc, gistxlogPage::num, palloc_array, RelationGetRelationName, ROTATEDIST, GistSplitVector::spl_lattr, GIST_SPLITVEC::spl_left, GistSplitVector::spl_lisnull, GIST_SPLITVEC::spl_nleft, GIST_SPLITVEC::spl_nright, GistSplitVector::spl_rattr, GIST_SPLITVEC::spl_right, GistSplitVector::spl_risnull, and GistSplitVector::splitVector.

Referenced by gist_indexsortbuild_levelstate_flush(), gistplacetopage(), and gistSplit().

◆ gistSplitByKey()

void gistSplitByKey ( Relation  r,
Page  page,
IndexTuple itup,
int  len,
GISTSTATE giststate,
GistSplitVector v,
int  attno 
)
extern

Definition at line 623 of file gistsplit.c.

625{
628 int nOffNullTuples = 0;
629 int i;
630
631 /* generate the item array, and identify tuples with null keys */
632 /* note that entryvec->vector[0] goes unused in this code */
633 entryvec = palloc(GEVHDRSZ + (len + 1) * sizeof(GISTENTRY));
634 entryvec->n = len + 1;
636
637 for (i = 1; i <= len; i++)
638 {
639 Datum datum;
640 bool IsNull;
641
642 datum = index_getattr(itup[i - 1], attno + 1, giststate->leafTupdesc,
643 &IsNull);
644 gistdentryinit(giststate, attno, &(entryvec->vector[i]),
645 datum, r, page, i,
646 false, IsNull);
647 if (IsNull)
649 }
650
651 if (nOffNullTuples == len)
652 {
653 /*
654 * Corner case: All keys in attno column are null, so just transfer
655 * our attention to the next column. If there's no next column, just
656 * split page in half.
657 */
658 v->spl_risnull[attno] = v->spl_lisnull[attno] = true;
659
660 if (attno + 1 < giststate->nonLeafTupdesc->natts)
661 gistSplitByKey(r, page, itup, len, giststate, v, attno + 1);
662 else
664 }
665 else if (nOffNullTuples > 0)
666 {
667 int j = 0;
668
669 /*
670 * We don't want to mix NULL and not-NULL keys on one page, so split
671 * nulls to right page and not-nulls to left.
672 */
675 v->spl_risnull[attno] = true;
676
678 v->splitVector.spl_nleft = 0;
679 for (i = 1; i <= len; i++)
680 if (j < v->splitVector.spl_nright && offNullTuples[j] == i)
681 j++;
682 else
684
685 /* Compute union keys, unless outer recursion level will handle it */
686 if (attno == 0 && giststate->nonLeafTupdesc->natts == 1)
687 {
688 v->spl_dontcare = NULL;
689 gistunionsubkey(giststate, itup, v);
690 }
691 }
692 else
693 {
694 /*
695 * All keys are not-null, so apply user-defined PickSplit method
696 */
697 if (gistUserPicksplit(r, entryvec, attno, v, itup, len, giststate))
698 {
699 /*
700 * Splitting on attno column is not optimal, so consider
701 * redistributing don't-care tuples according to the next column
702 */
703 Assert(attno + 1 < giststate->nonLeafTupdesc->natts);
704
705 if (v->spl_dontcare == NULL)
706 {
707 /*
708 * This split was actually degenerate, so ignore it altogether
709 * and just split according to the next column.
710 */
711 gistSplitByKey(r, page, itup, len, giststate, v, attno + 1);
712 }
713 else
714 {
715 /*
716 * Form an array of just the don't-care tuples to pass to a
717 * recursive invocation of this function for the next column.
718 */
720 OffsetNumber *map = (OffsetNumber *) palloc(len * sizeof(OffsetNumber));
721 int newlen = 0;
723
724 for (i = 0; i < len; i++)
725 {
726 if (v->spl_dontcare[i + 1])
727 {
728 newitup[newlen] = itup[i];
729 map[newlen] = i + 1;
730 newlen++;
731 }
732 }
733
734 Assert(newlen > 0);
735
736 /*
737 * Make a backup copy of v->splitVector, since the recursive
738 * call will overwrite that with its own result.
739 */
745
746 /* Recursively decide how to split the don't-care tuples */
747 gistSplitByKey(r, page, newitup, newlen, giststate, v, attno + 1);
748
749 /* Merge result of subsplit with non-don't-care tuples */
750 for (i = 0; i < v->splitVector.spl_nleft; i++)
751 backupSplit.spl_left[backupSplit.spl_nleft++] = map[v->splitVector.spl_left[i] - 1];
752 for (i = 0; i < v->splitVector.spl_nright; i++)
753 backupSplit.spl_right[backupSplit.spl_nright++] = map[v->splitVector.spl_right[i] - 1];
754
756 }
757 }
758 }
759
760 /*
761 * If we're handling a multicolumn index, at the end of the recursion
762 * recompute the left and right union datums for all index columns. This
763 * makes sure we hand back correct union datums in all corner cases,
764 * including when we haven't processed all columns to start with, or when
765 * a secondary split moved "don't care" tuples from one side to the other
766 * (we really shouldn't assume that that didn't change the union datums).
767 *
768 * Note: when we're in an internal recursion (attno > 0), we do not worry
769 * about whether the union datums we return with are sensible, since
770 * calling levels won't care. Also, in a single-column index, we expect
771 * that PickSplit (or the special cases above) produced correct union
772 * datums.
773 */
774 if (attno == 0 && giststate->nonLeafTupdesc->natts > 1)
775 {
776 v->spl_dontcare = NULL;
777 gistunionsubkey(giststate, itup, v);
778 }
779}
static void gistunionsubkey(GISTSTATE *giststate, IndexTuple *itvec, GistSplitVector *spl)
Definition gistsplit.c:80
static bool gistUserPicksplit(Relation r, GistEntryVector *entryvec, int attno, GistSplitVector *v, IndexTuple *itup, int len, GISTSTATE *giststate)
Definition gistsplit.c:415
static void gistSplitHalf(GIST_SPLITVEC *v, int len)
Definition gistsplit.c:585

References Assert, fb(), GEVHDRSZ, gistdentryinit(), gistSplitByKey(), gistSplitHalf(), gistunionsubkey(), gistUserPicksplit(), i, index_getattr(), j, GISTSTATE::leafTupdesc, len, TupleDescData::natts, GISTSTATE::nonLeafTupdesc, palloc(), palloc_array, GistSplitVector::spl_dontcare, GIST_SPLITVEC::spl_left, GistSplitVector::spl_lisnull, GIST_SPLITVEC::spl_nleft, GIST_SPLITVEC::spl_nright, GIST_SPLITVEC::spl_right, GistSplitVector::spl_risnull, and GistSplitVector::splitVector.

Referenced by gistSplit(), and gistSplitByKey().

◆ gistunion()

IndexTuple gistunion ( Relation  r,
IndexTuple itvec,
int  len,
GISTSTATE giststate 
)
extern

Definition at line 219 of file gistutil.c.

220{
221 Datum attr[INDEX_MAX_KEYS];
222 bool isnull[INDEX_MAX_KEYS];
223
224 gistMakeUnionItVec(giststate, itvec, len, attr, isnull);
225
226 return gistFormTuple(giststate, r, attr, isnull, false);
227}
void gistMakeUnionItVec(GISTSTATE *giststate, IndexTuple *itvec, int len, Datum *attr, bool *isnull)
Definition gistutil.c:155

References fb(), gistFormTuple(), gistMakeUnionItVec(), INDEX_MAX_KEYS, and len.

Referenced by gist_indexsortbuild_levelstate_flush().

◆ gistUnloadNodeBuffers()

void gistUnloadNodeBuffers ( GISTBuildBuffers gfbb)
extern

Definition at line 270 of file gistbuildbuffers.c.

271{
272 int i;
273
274 /* Unload all the buffers that have a page loaded in memory. */
275 for (i = 0; i < gfbb->loadedBuffersCount; i++)
277
278 /* Now there are no node buffers with loaded last page */
279 gfbb->loadedBuffersCount = 0;
280}
static void gistUnloadNodeBuffer(GISTBuildBuffers *gfbb, GISTNodeBuffer *nodeBuffer)

References gistUnloadNodeBuffer(), i, GISTBuildBuffers::loadedBuffers, and GISTBuildBuffers::loadedBuffersCount.

Referenced by gistProcessEmptyingQueue().

◆ gistvacuumcleanup()

IndexBulkDeleteResult * gistvacuumcleanup ( IndexVacuumInfo info,
IndexBulkDeleteResult stats 
)
extern

Definition at line 75 of file gistvacuum.c.

76{
77 /* No-op in ANALYZE ONLY mode */
78 if (info->analyze_only)
79 return stats;
80
81 /*
82 * If gistbulkdelete was called, we need not do anything, just return the
83 * stats from the latest gistbulkdelete call. If it wasn't called, we
84 * still need to do a pass over the index, to obtain index statistics.
85 */
86 if (stats == NULL)
87 {
89 gistvacuumscan(info, stats, NULL, NULL);
90 }
91
92 /*
93 * It's quite possible for us to be fooled by concurrent page splits into
94 * double-counting some index tuples, so disbelieve any total that exceeds
95 * the underlying heap's count ... if we know that accurately. Otherwise
96 * this might just make matters worse.
97 */
98 if (!info->estimated_count)
99 {
100 if (stats->num_index_tuples > info->num_heap_tuples)
101 stats->num_index_tuples = info->num_heap_tuples;
102 }
103
104 return stats;
105}
double num_index_tuples
Definition genam.h:85
double num_heap_tuples
Definition genam.h:58
bool analyze_only
Definition genam.h:54
bool estimated_count
Definition genam.h:56

References IndexVacuumInfo::analyze_only, IndexVacuumInfo::estimated_count, fb(), gistvacuumscan(), IndexVacuumInfo::num_heap_tuples, IndexBulkDeleteResult::num_index_tuples, and palloc0_object.

Referenced by gisthandler().

◆ gistvalidate()

bool gistvalidate ( Oid  opclassoid)
extern

Definition at line 32 of file gistvalidate.c.

33{
34 bool result = true;
38 Oid opcintype;
40 char *opclassname;
41 char *opfamilyname;
43 *oprlist;
46 int i;
47 ListCell *lc;
48
49 /* Fetch opclass information */
52 elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
54
55 opfamilyoid = classform->opcfamily;
56 opcintype = classform->opcintype;
57 opckeytype = classform->opckeytype;
59 opckeytype = opcintype;
60 opclassname = NameStr(classform->opcname);
61
62 /* Fetch opfamily information */
63 opfamilyname = get_opfamily_name(opfamilyoid, false);
64
65 /* Fetch all operators and support functions of the opfamily */
68
69 /* Check individual support functions */
70 for (i = 0; i < proclist->n_members; i++)
71 {
72 HeapTuple proctup = &proclist->members[i]->tuple;
74 bool ok;
75
76 /*
77 * All GiST support functions should be registered with matching
78 * left/right types
79 */
80 if (procform->amproclefttype != procform->amprocrighttype)
81 {
84 errmsg("operator family \"%s\" of access method %s contains support function %s with different left and right input types",
85 opfamilyname, "gist",
86 format_procedure(procform->amproc))));
87 result = false;
88 }
89
90 /*
91 * We can't check signatures except within the specific opclass, since
92 * we need to know the associated opckeytype in many cases.
93 */
94 if (procform->amproclefttype != opcintype)
95 continue;
96
97 /* Check procedure numbers and function signatures */
98 switch (procform->amprocnum)
99 {
101 ok = check_amproc_signature(procform->amproc, BOOLOID, false,
102 5, 5, INTERNALOID, opcintype,
104 break;
105 case GIST_UNION_PROC:
107 2, 2, INTERNALOID, INTERNALOID);
108 break;
111 case GIST_FETCH_PROC:
113 1, 1, INTERNALOID);
114 break;
117 3, 3, INTERNALOID,
119 break;
122 2, 2, INTERNALOID, INTERNALOID);
123 break;
124 case GIST_EQUAL_PROC:
126 3, 3, opckeytype, opckeytype,
128 break;
131 5, 5, INTERNALOID, opcintype,
133 break;
136 break;
138 ok = check_amproc_signature(procform->amproc, VOIDOID, true,
139 1, 1, INTERNALOID);
140 break;
142 ok = check_amproc_signature(procform->amproc, INT2OID, true,
143 1, 1, INT4OID) &&
144 procform->amproclefttype == ANYOID &&
145 procform->amprocrighttype == ANYOID;
146 break;
147 default:
150 errmsg("operator family \"%s\" of access method %s contains function %s with invalid support number %d",
151 opfamilyname, "gist",
152 format_procedure(procform->amproc),
153 procform->amprocnum)));
154 result = false;
155 continue; /* don't want additional message */
156 }
157
158 if (!ok)
159 {
162 errmsg("operator family \"%s\" of access method %s contains function %s with wrong signature for support number %d",
163 opfamilyname, "gist",
164 format_procedure(procform->amproc),
165 procform->amprocnum)));
166 result = false;
167 }
168 }
169
170 /* Check individual operators */
171 for (i = 0; i < oprlist->n_members; i++)
172 {
173 HeapTuple oprtup = &oprlist->members[i]->tuple;
176
177 /* TODO: Check that only allowed strategy numbers exist */
178 if (oprform->amopstrategy < 1)
179 {
182 errmsg("operator family \"%s\" of access method %s contains operator %s with invalid strategy number %d",
183 opfamilyname, "gist",
184 format_operator(oprform->amopopr),
185 oprform->amopstrategy)));
186 result = false;
187 }
188
189 /* GiST supports ORDER BY operators */
190 if (oprform->amoppurpose != AMOP_SEARCH)
191 {
192 /* ... but must have matching distance proc */
194 oprform->amoplefttype,
195 oprform->amoplefttype,
197 {
200 errmsg("operator family \"%s\" of access method %s contains unsupported ORDER BY specification for operator %s",
201 opfamilyname, "gist",
202 format_operator(oprform->amopopr))));
203 result = false;
204 }
205 /* ... and operator result must match the claimed btree opfamily */
207 if (!opfamily_can_sort_type(oprform->amopsortfamily, op_rettype))
208 {
211 errmsg("operator family \"%s\" of access method %s contains incorrect ORDER BY opfamily specification for operator %s",
212 opfamilyname, "gist",
213 format_operator(oprform->amopopr))));
214 result = false;
215 }
216 }
217 else
218 {
219 /* Search operators must always return bool */
221 }
222
223 /* Check operator signature */
225 oprform->amoplefttype,
226 oprform->amoprighttype))
227 {
230 errmsg("operator family \"%s\" of access method %s contains operator %s with wrong signature",
231 opfamilyname, "gist",
232 format_operator(oprform->amopopr))));
233 result = false;
234 }
235 }
236
237 /* Now check for inconsistent groups of operators/functions */
240 foreach(lc, grouplist)
241 {
243
244 /* Remember the group exactly matching the test opclass */
245 if (thisgroup->lefttype == opcintype &&
246 thisgroup->righttype == opcintype)
248
249 /*
250 * There is not a lot we can do to check the operator sets, since each
251 * GiST opclass is more or less a law unto itself, and some contain
252 * only operators that are binary-compatible with the opclass datatype
253 * (meaning that empty operator sets can be OK). That case also means
254 * that we shouldn't insist on nonempty function sets except for the
255 * opclass's own group.
256 */
257 }
258
259 /* Check that the originally-named opclass is complete */
260 for (i = 1; i <= GISTNProcs; i++)
261 {
262 if (opclassgroup &&
263 (opclassgroup->functionset & (((uint64) 1) << i)) != 0)
264 continue; /* got it */
265 if (i == GIST_DISTANCE_PROC || i == GIST_FETCH_PROC ||
269 continue; /* optional methods */
272 errmsg("operator class \"%s\" of access method %s is missing support function %d",
273 opclassname, "gist", i)));
274 result = false;
275 }
276
280
281 return result;
282}
bool check_amproc_signature(Oid funcid, Oid restype, bool exact, int minargs, int maxargs,...)
Definition amvalidate.c:152
bool check_amop_signature(Oid opno, Oid restype, Oid lefttype, Oid righttype)
Definition amvalidate.c:206
List * identify_opfamily_groups(CatCList *oprlist, CatCList *proclist)
Definition amvalidate.c:43
bool opfamily_can_sort_type(Oid opfamilyoid, Oid datatypeoid)
Definition amvalidate.c:271
bool check_amoptsproc_signature(Oid funcid)
Definition amvalidate.c:192
#define NameStr(name)
Definition c.h:765
uint64_t uint64
Definition c.h:547
void ReleaseCatCacheList(CatCList *list)
Definition catcache.c:2114
#define INFO
Definition elog.h:34
#define GISTNProcs
Definition gist.h:44
#define HeapTupleIsValid(tuple)
Definition htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
Oid get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, int16 procnum)
Definition lsyscache.c:872
Oid get_op_rettype(Oid opno)
Definition lsyscache.c:1483
char * get_opfamily_name(Oid opfid, bool missing_ok)
Definition lsyscache.c:1403
FormData_pg_amop * Form_pg_amop
Definition pg_amop.h:88
FormData_pg_amproc * Form_pg_amproc
Definition pg_amproc.h:68
FormData_pg_opclass * Form_pg_opclass
Definition pg_opclass.h:83
char * format_procedure(Oid procedure_oid)
Definition regproc.c:305
char * format_operator(Oid operator_oid)
Definition regproc.c:801
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:264
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition syscache.c:220
#define SearchSysCacheList1(cacheId, key1)
Definition syscache.h:127

References check_amop_signature(), check_amoptsproc_signature(), check_amproc_signature(), elog, ereport, errcode(), errmsg(), ERROR, fb(), format_operator(), format_procedure(), get_op_rettype(), get_opfamily_name(), get_opfamily_proc(), GETSTRUCT(), GIST_COMPRESS_PROC, GIST_CONSISTENT_PROC, GIST_DECOMPRESS_PROC, GIST_DISTANCE_PROC, GIST_EQUAL_PROC, GIST_FETCH_PROC, GIST_OPTIONS_PROC, GIST_PENALTY_PROC, GIST_PICKSPLIT_PROC, GIST_SORTSUPPORT_PROC, GIST_TRANSLATE_CMPTYPE_PROC, GIST_UNION_PROC, GISTNProcs, HeapTupleIsValid, i, identify_opfamily_groups(), INFO, lfirst, NameStr, ObjectIdGetDatum(), OidIsValid, opfamily_can_sort_type(), ReleaseCatCacheList(), ReleaseSysCache(), SearchSysCache1(), and SearchSysCacheList1.

Referenced by gisthandler().

◆ gistXLogAssignLSN()

XLogRecPtr gistXLogAssignLSN ( void  )
extern

Definition at line 574 of file gistxlog.c.

575{
576 int dummy = 0;
577
578 /*
579 * Records other than XLOG_SWITCH must have content. We use an integer 0
580 * to follow the restriction.
581 */
584 XLogRegisterData(&dummy, sizeof(dummy));
586}
#define XLOG_GIST_ASSIGN_LSN
Definition gistxlog.h:27
#define XLOG_MARK_UNIMPORTANT
Definition xlog.h:166
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition xloginsert.c:478
void XLogRegisterData(const void *data, uint32 len)
Definition xloginsert.c:368
void XLogSetRecordFlags(uint8 flags)
Definition xloginsert.c:460
void XLogBeginInsert(void)
Definition xloginsert.c:152

References fb(), XLOG_GIST_ASSIGN_LSN, XLOG_MARK_UNIMPORTANT, XLogBeginInsert(), XLogInsert(), XLogRegisterData(), and XLogSetRecordFlags().

Referenced by gistGetFakeLSN().

◆ gistXLogDelete()

XLogRecPtr gistXLogDelete ( Buffer  buffer,
OffsetNumber todelete,
int  ntodelete,
TransactionId  snapshotConflictHorizon,
Relation  heaprel 
)
extern

Definition at line 668 of file gistxlog.c.

670{
673
675 xlrec.snapshotConflictHorizon = snapshotConflictHorizon;
676 xlrec.ntodelete = ntodelete;
677
680
681 /*
682 * We need the target-offsets array whether or not we store the whole
683 * buffer, to allow us to find the snapshotConflictHorizon on a standby
684 * server.
685 */
686 XLogRegisterData(todelete, ntodelete * sizeof(OffsetNumber));
687
689
691
692 return recptr;
693}
#define SizeOfGistxlogDelete
Definition gistxlog.h:59
#define XLOG_GIST_DELETE
Definition gistxlog.h:21
#define RelationIsAccessibleInLogicalDecoding(relation)
Definition rel.h:693
bool isCatalogRel
Definition gistxlog.h:52
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition xloginsert.c:245
#define REGBUF_STANDARD
Definition xloginsert.h:35

References fb(), gistxlogDelete::isCatalogRel, REGBUF_STANDARD, RelationIsAccessibleInLogicalDecoding, SizeOfGistxlogDelete, XLOG_GIST_DELETE, XLogBeginInsert(), XLogInsert(), XLogRegisterBuffer(), and XLogRegisterData().

Referenced by gistprunepage().

◆ gistXLogPageDelete()

XLogRecPtr gistXLogPageDelete ( Buffer  buffer,
FullTransactionId  xid,
Buffer  parentBuffer,
OffsetNumber  downlinkOffset 
)
extern

Definition at line 550 of file gistxlog.c.

552{
555
556 xlrec.deleteXid = xid;
557 xlrec.downlinkOffset = downlinkOffset;
558
561
564
566
567 return recptr;
568}
#define SizeOfGistxlogPageDelete
Definition gistxlog.h:91
#define XLOG_GIST_PAGE_DELETE
Definition gistxlog.h:26
FullTransactionId deleteXid
Definition gistxlog.h:86

References gistxlogPageDelete::deleteXid, fb(), REGBUF_STANDARD, SizeOfGistxlogPageDelete, XLOG_GIST_PAGE_DELETE, XLogBeginInsert(), XLogInsert(), XLogRegisterBuffer(), and XLogRegisterData().

Referenced by gistdeletepage().

◆ gistXLogPageReuse()

void gistXLogPageReuse ( Relation  rel,
Relation  heaprel,
BlockNumber  blkno,
FullTransactionId  deleteXid 
)
extern

Definition at line 592 of file gistxlog.c.

594{
596
597 /*
598 * Note that we don't register the buffer with the record, because this
599 * operation doesn't modify the page. This record only exists to provide a
600 * conflict point for Hot Standby.
601 */
602
603 /* XLOG stuff */
605 xlrec_reuse.locator = rel->rd_locator;
606 xlrec_reuse.block = blkno;
607 xlrec_reuse.snapshotConflictHorizon = deleteXid;
608
611
613}
#define XLOG_GIST_PAGE_REUSE
Definition gistxlog.h:22
#define SizeOfGistxlogPageReuse
Definition gistxlog.h:106
RelFileLocator rd_locator
Definition rel.h:57

References fb(), gistxlogPageReuse::isCatalogRel, RelationData::rd_locator, RelationIsAccessibleInLogicalDecoding, SizeOfGistxlogPageReuse, XLOG_GIST_PAGE_REUSE, XLogBeginInsert(), XLogInsert(), and XLogRegisterData().

Referenced by gistNewBuffer().

◆ gistXLogSplit()

XLogRecPtr gistXLogSplit ( bool  page_is_leaf,
SplitPageLayout dist,
BlockNumber  origrlink,
GistNSN  orignsn,
Buffer  leftchildbuf,
bool  markfollowright 
)
extern

Definition at line 493 of file gistxlog.c.

497{
499 SplitPageLayout *ptr;
500 int npage = 0;
502 int i;
503
504 for (ptr = dist; ptr; ptr = ptr->next)
505 npage++;
506
507 xlrec.origrlink = origrlink;
508 xlrec.orignsn = orignsn;
509 xlrec.origleaf = page_is_leaf;
510 xlrec.npage = (uint16) npage;
511 xlrec.markfollowright = markfollowright;
512
514
515 /*
516 * Include a full page image of the child buf. (only necessary if a
517 * checkpoint happened since the child page was split)
518 */
521
522 /*
523 * NOTE: We register a lot of data. The caller must've called
524 * XLogEnsureRecordSpace() to prepare for that. We cannot do it here,
525 * because we're already in a critical section. If you change the number
526 * of buffer or data registrations here, make sure you modify the
527 * XLogEnsureRecordSpace() calls accordingly!
528 */
530
531 i = 1;
532 for (ptr = dist; ptr; ptr = ptr->next)
533 {
535 XLogRegisterBufData(i, &(ptr->block.num), sizeof(int));
536 XLogRegisterBufData(i, ptr->list, ptr->lenlist);
537 i++;
538 }
539
541
542 return recptr;
543}
uint16_t uint16
Definition c.h:545
#define XLOG_GIST_PAGE_SPLIT
Definition gistxlog.h:23
struct SplitPageLayout * next
void XLogRegisterBufData(uint8 block_id, const void *data, uint32 len)
Definition xloginsert.c:409
#define REGBUF_WILL_INIT
Definition xloginsert.h:34

References SplitPageLayout::block, SplitPageLayout::buffer, BufferIsValid(), fb(), i, SplitPageLayout::lenlist, SplitPageLayout::list, SplitPageLayout::next, gistxlogPage::num, REGBUF_STANDARD, REGBUF_WILL_INIT, XLOG_GIST_PAGE_SPLIT, XLogBeginInsert(), XLogInsert(), XLogRegisterBufData(), XLogRegisterBuffer(), and XLogRegisterData().

Referenced by gistplacetopage().

◆ gistXLogUpdate()

XLogRecPtr gistXLogUpdate ( Buffer  buffer,
OffsetNumber todelete,
int  ntodelete,
IndexTuple itup,
int  ituplen,
Buffer  leftchildbuf 
)
extern

Definition at line 627 of file gistxlog.c.

631{
633 int i;
635
636 xlrec.ntodelete = ntodelete;
637 xlrec.ntoinsert = ituplen;
638
641
643 XLogRegisterBufData(0, todelete, sizeof(OffsetNumber) * ntodelete);
644
645 /* new tuples */
646 for (i = 0; i < ituplen; i++)
647 XLogRegisterBufData(0, itup[i], IndexTupleSize(itup[i]));
648
649 /*
650 * Include a full page image of the child buf. (only necessary if a
651 * checkpoint happened since the child page was split)
652 */
655
657
658 return recptr;
659}
#define XLOG_GIST_PAGE_UPDATE
Definition gistxlog.h:20

References BufferIsValid(), fb(), i, IndexTupleSize(), gistxlogPageUpdate::ntodelete, REGBUF_STANDARD, XLOG_GIST_PAGE_UPDATE, XLogBeginInsert(), XLogInsert(), XLogRegisterBufData(), XLogRegisterBuffer(), and XLogRegisterData().

Referenced by gistplacetopage(), and gistvacuumpage().

◆ initGISTstate()

GISTSTATE * initGISTstate ( Relation  index)
extern

Definition at line 1537 of file gist.c.

1538{
1539 GISTSTATE *giststate;
1540 MemoryContext scanCxt;
1542 int i;
1543
1544 /* safety check to protect fixed-size arrays in GISTSTATE */
1545 if (index->rd_att->natts > INDEX_MAX_KEYS)
1546 elog(ERROR, "numberOfAttributes %d > %d",
1547 index->rd_att->natts, INDEX_MAX_KEYS);
1548
1549 /* Create the memory context that will hold the GISTSTATE */
1551 "GiST scan context",
1553 oldCxt = MemoryContextSwitchTo(scanCxt);
1554
1555 /* Create and fill in the GISTSTATE */
1556 giststate = palloc_object(GISTSTATE);
1557
1558 giststate->scanCxt = scanCxt;
1559 giststate->tempCxt = scanCxt; /* caller must change this if needed */
1560 giststate->leafTupdesc = index->rd_att;
1561
1562 /*
1563 * The truncated tupdesc for non-leaf index tuples, which doesn't contain
1564 * the INCLUDE attributes.
1565 *
1566 * It is used to form tuples during tuple adjustment and page split.
1567 * B-tree creates shortened tuple descriptor for every truncated tuple,
1568 * because it is doing this less often: it does not have to form truncated
1569 * tuples during page split. Also, B-tree is not adjusting tuples on
1570 * internal pages the way GiST does.
1571 */
1574
1576 {
1577 fmgr_info_copy(&(giststate->consistentFn[i]),
1579 scanCxt);
1580 fmgr_info_copy(&(giststate->unionFn[i]),
1582 scanCxt);
1583
1584 /* opclasses are not required to provide a Compress method */
1586 fmgr_info_copy(&(giststate->compressFn[i]),
1588 scanCxt);
1589 else
1590 giststate->compressFn[i].fn_oid = InvalidOid;
1591
1592 /* opclasses are not required to provide a Decompress method */
1594 fmgr_info_copy(&(giststate->decompressFn[i]),
1596 scanCxt);
1597 else
1598 giststate->decompressFn[i].fn_oid = InvalidOid;
1599
1600 fmgr_info_copy(&(giststate->penaltyFn[i]),
1602 scanCxt);
1603 fmgr_info_copy(&(giststate->picksplitFn[i]),
1605 scanCxt);
1606 fmgr_info_copy(&(giststate->equalFn[i]),
1608 scanCxt);
1609
1610 /* opclasses are not required to provide a Distance method */
1612 fmgr_info_copy(&(giststate->distanceFn[i]),
1614 scanCxt);
1615 else
1616 giststate->distanceFn[i].fn_oid = InvalidOid;
1617
1618 /* opclasses are not required to provide a Fetch method */
1620 fmgr_info_copy(&(giststate->fetchFn[i]),
1622 scanCxt);
1623 else
1624 giststate->fetchFn[i].fn_oid = InvalidOid;
1625
1626 /*
1627 * If the index column has a specified collation, we should honor that
1628 * while doing comparisons. However, we may have a collatable storage
1629 * type for a noncollatable indexed data type. If there's no index
1630 * collation then specify default collation in case the support
1631 * functions need collation. This is harmless if the support
1632 * functions don't care about collation, so we just do it
1633 * unconditionally. (We could alternatively call get_typcollation,
1634 * but that seems like expensive overkill --- there aren't going to be
1635 * any cases where a GiST storage type has a nondefault collation.)
1636 */
1637 if (OidIsValid(index->rd_indcollation[i]))
1638 giststate->supportCollation[i] = index->rd_indcollation[i];
1639 else
1641 }
1642
1643 /* No opclass information for INCLUDE attributes */
1644 for (; i < index->rd_att->natts; i++)
1645 {
1646 giststate->consistentFn[i].fn_oid = InvalidOid;
1647 giststate->unionFn[i].fn_oid = InvalidOid;
1648 giststate->compressFn[i].fn_oid = InvalidOid;
1649 giststate->decompressFn[i].fn_oid = InvalidOid;
1650 giststate->penaltyFn[i].fn_oid = InvalidOid;
1651 giststate->picksplitFn[i].fn_oid = InvalidOid;
1652 giststate->equalFn[i].fn_oid = InvalidOid;
1653 giststate->distanceFn[i].fn_oid = InvalidOid;
1654 giststate->fetchFn[i].fn_oid = InvalidOid;
1655 giststate->supportCollation[i] = InvalidOid;
1656 }
1657
1659
1660 return giststate;
1661}
void fmgr_info_copy(FmgrInfo *dstinfo, FmgrInfo *srcinfo, MemoryContext destcxt)
Definition fmgr.c:581
FmgrInfo * index_getprocinfo(Relation irel, AttrNumber attnum, uint16 procnum)
Definition indexam.c:917
FmgrInfo distanceFn[INDEX_MAX_KEYS]
FmgrInfo consistentFn[INDEX_MAX_KEYS]
FmgrInfo picksplitFn[INDEX_MAX_KEYS]
TupleDesc CreateTupleDescTruncatedCopy(TupleDesc tupdesc, int natts)
Definition tupdesc.c:296

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, GISTSTATE::compressFn, GISTSTATE::consistentFn, CreateTupleDescTruncatedCopy(), CurrentMemoryContext, GISTSTATE::decompressFn, GISTSTATE::distanceFn, elog, GISTSTATE::equalFn, ERROR, fb(), GISTSTATE::fetchFn, fmgr_info_copy(), FmgrInfo::fn_oid, GIST_COMPRESS_PROC, GIST_CONSISTENT_PROC, GIST_DECOMPRESS_PROC, GIST_DISTANCE_PROC, GIST_EQUAL_PROC, GIST_FETCH_PROC, GIST_PENALTY_PROC, GIST_PICKSPLIT_PROC, GIST_UNION_PROC, i, index_getprocid(), index_getprocinfo(), INDEX_MAX_KEYS, IndexRelationGetNumberOfKeyAttributes, InvalidOid, GISTSTATE::leafTupdesc, MemoryContextSwitchTo(), GISTSTATE::nonLeafTupdesc, OidIsValid, palloc_object, GISTSTATE::penaltyFn, GISTSTATE::picksplitFn, GISTSTATE::scanCxt, GISTSTATE::supportCollation, GISTSTATE::tempCxt, and GISTSTATE::unionFn.

Referenced by gistbeginscan(), gistbuild(), and gistinsert().