PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
gist_private.h File Reference
#include "access/amapi.h"
#include "access/gist.h"
#include "access/itup.h"
#include "fmgr.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  SplitedPageLayout
 
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)   (offsetof(GISTSearchItem, distances) + sizeof(double) * (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 SplitedPageLayout SplitedPageLayout
 
typedef struct GISTInsertStack GISTInsertStack
 
typedef struct GistSplitVector GistSplitVector
 
typedef struct GISTBuildBuffers GISTBuildBuffers
 
typedef struct GiSTOptions GiSTOptions
 

Functions

void gistbuildempty (Relation index)
 
bool gistinsert (Relation r, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, IndexUniqueCheck checkUnique, struct IndexInfo *indexInfo)
 
MemoryContext createTempGistContext (void)
 
GISTSTATEinitGISTstate (Relation index)
 
void freeGISTstate (GISTSTATE *giststate)
 
void gistdoinsert (Relation r, IndexTuple itup, Size freespace, GISTSTATE *GISTstate)
 
bool gistplacetopage (Relation rel, Size freespace, GISTSTATE *giststate, Buffer buffer, IndexTuple *itup, int ntup, OffsetNumber oldoffnum, BlockNumber *newblkno, Buffer leftchildbuf, List **splitinfo, bool markleftchild)
 
SplitedPageLayoutgistSplit (Relation r, Page page, IndexTuple *itup, int len, GISTSTATE *giststate)
 
XLogRecPtr gistXLogUpdate (Buffer buffer, OffsetNumber *todelete, int ntodelete, IndexTuple *itup, int ntup, Buffer leftchild)
 
XLogRecPtr gistXLogSplit (bool page_is_leaf, SplitedPageLayout *dist, BlockNumber origrlink, GistNSN oldnsn, Buffer leftchild, bool markfollowright)
 
bool gistgettuple (IndexScanDesc scan, ScanDirection dir)
 
int64 gistgetbitmap (IndexScanDesc scan, TIDBitmap *tbm)
 
bool gistcanreturn (Relation index, int attno)
 
bool gistvalidate (Oid opclassoid)
 
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)
 
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, Datum *attdata, bool *isnull, bool isleaf)
 
OffsetNumber gistchoose (Relation r, Page p, IndexTuple it, GISTSTATE *giststate)
 
void GISTInitBuffer (Buffer b, 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 *key1, bool isNull1, GISTENTRY *key2, bool isNull2)
 
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)
 
IndexTuple 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)
 
void gistValidateBufferingOption (char *value)
 
GISTBuildBuffersgistInitBuildBuffers (int pagesPerBuffer, int levelStep, int maxLevel)
 
GISTNodeBuffergistGetNodeBuffer (GISTBuildBuffers *gfbb, GISTSTATE *giststate, BlockNumber blkno, int level)
 
void gistPushItupToNodeBuffer (GISTBuildBuffers *gfbb, GISTNodeBuffer *nodeBuffer, IndexTuple item)
 
bool gistPopItupFromNodeBuffer (GISTBuildBuffers *gfbb, GISTNodeBuffer *nodeBuffer, IndexTuple *item)
 
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

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

Definition at line 311 of file gist_private.h.

Referenced by gistPushItupToNodeBuffer().

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

Definition at line 319 of file gist_private.h.

Referenced by gistProcessItup().

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

Definition at line 436 of file gist_private.h.

Referenced by gistbuild().

#define GIST_MAX_SPLIT_PAGES   75

Definition at line 40 of file gist_private.h.

Referenced by gistplacetopage().

#define GIST_MIN_FILLFACTOR   10

Definition at line 435 of file gist_private.h.

#define GIST_UNLOCK   BUFFER_LOCK_UNLOCK
#define GiSTPageSize   ( BLCKSZ - SizeOfPageHeaderData - MAXALIGN(sizeof(GISTPageOpaqueData)) )

Definition at line 432 of file gist_private.h.

Referenced by gistfitpage(), and gistSplit().

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

Definition at line 143 of file gist_private.h.

Referenced by getNextNearest(), gistScanPage(), and pairingheap_GISTSearchItem_cmp().

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

Definition at line 275 of file gist_private.h.

Referenced by gistbulkdelete(), gistdoinsert(), and gistindex_keytest().

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

Definition at line 276 of file gist_private.h.

Referenced by gistformdownlink(), and gistplacetopage().

#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:126

Definition at line 306 of file gist_private.h.

Referenced by gistProcessItup(), and gistRelocateBuildBuffersOnSplit().

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

Definition at line 58 of file gist_private.h.

Referenced by gistGetItupFromPage(), and gistPopItupFromNodeBuffer().

#define PAGE_NO_SPACE (   nbp,
  itup 
)
Value:
#define PAGE_FREE_SPACE(nbp)
Definition: gist_private.h:56
#define MAXALIGN(LEN)
Definition: c.h:584
#define IndexTupleSize(itup)
Definition: itup.h:70

Definition at line 60 of file gist_private.h.

Referenced by gistPushItupToNodeBuffer().

#define SizeOfGISTSearchItem (   n_distances)    (offsetof(GISTSearchItem, distances) + sizeof(double) * (n_distances))

Definition at line 145 of file gist_private.h.

Referenced by gistScanPage().

#define TUPLE_IS_INVALID   0xfffe

Definition at line 273 of file gist_private.h.

#define TUPLE_IS_VALID   0xffff

Definition at line 272 of file gist_private.h.

Typedef Documentation

Function Documentation

MemoryContext createTempGistContext ( void  )

Definition at line 110 of file gist.c.

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate(), and CurrentMemoryContext.

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

111 {
113  "GiST temporary context",
115 }
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:145
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:440
void freeGISTstate ( GISTSTATE giststate)

Definition at line 1510 of file gist.c.

References MemoryContextDelete(), and GISTSTATE::scanCxt.

Referenced by gistbuild(), and gistendscan().

1511 {
1512  /* It's sufficient to delete the scanCxt */
1513  MemoryContextDelete(giststate->scanCxt);
1514 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:200
MemoryContext scanCxt
Definition: gist_private.h:78
IndexBuildResult* gistbuild ( Relation  heap,
Relation  index,
struct IndexInfo indexInfo 
)

Definition at line 114 of file gistbuild.c.

References Assert, BufferGetBlockNumber(), BufferGetPage, GISTBuildState::bufferingMode, GiSTOptions::bufferingModeOffset, createTempGistContext(), CurrentMemoryContext, DEBUG1, elog, END_CRIT_SECTION, ERROR, F_LEAF, fillfactor, GiSTOptions::fillfactor, freeGISTstate(), GISTBuildState::freespace, GISTBuildState::gfbb, GIST_BUFFERING_ACTIVE, GIST_BUFFERING_AUTO, GIST_BUFFERING_DISABLED, GIST_BUFFERING_STATS, GIST_DEFAULT_FILLFACTOR, GIST_ROOT_BLKNO, gistBuildCallback(), gistEmptyAllBuffers(), gistFreeBuildBuffers(), gistGetFakeLSN(), GISTInitBuffer(), gistNewBuffer(), GISTBuildState::giststate, IndexBuildResult::heap_tuples, IndexBuildResult::index_tuples, IndexBuildHeapScan(), GISTBuildState::indexrel, GISTBuildState::indtuples, GISTBuildState::indtuplesSize, initGISTstate(), MarkBufferDirty(), MemoryContextDelete(), MemoryContextSwitchTo(), PageSetLSN, palloc(), RelationData::rd_options, REGBUF_WILL_INIT, RelationGetNumberOfBlocks, RelationGetRelationName, RelationNeedsWAL, START_CRIT_SECTION, GISTSTATE::tempCxt, UnlockReleaseBuffer(), XLOG_GIST_CREATE_INDEX, XLogBeginInsert(), XLogInsert(), and XLogRegisterBuffer().

Referenced by gisthandler().

115 {
116  IndexBuildResult *result;
117  double reltuples;
118  GISTBuildState buildstate;
119  Buffer buffer;
120  Page page;
122  int fillfactor;
123 
124  buildstate.indexrel = index;
125  if (index->rd_options)
126  {
127  /* Get buffering mode from the options string */
129  char *bufferingMode = (char *) options + options->bufferingModeOffset;
130 
131  if (strcmp(bufferingMode, "on") == 0)
132  buildstate.bufferingMode = GIST_BUFFERING_STATS;
133  else if (strcmp(bufferingMode, "off") == 0)
135  else
136  buildstate.bufferingMode = GIST_BUFFERING_AUTO;
137 
138  fillfactor = options->fillfactor;
139  }
140  else
141  {
142  /*
143  * By default, switch to buffering mode when the index grows too large
144  * to fit in cache.
145  */
146  buildstate.bufferingMode = GIST_BUFFERING_AUTO;
147  fillfactor = GIST_DEFAULT_FILLFACTOR;
148  }
149  /* Calculate target amount of free space to leave on pages */
150  buildstate.freespace = BLCKSZ * (100 - fillfactor) / 100;
151 
152  /*
153  * We expect to be called exactly once for any index relation. If that's
154  * not the case, big trouble's what we have.
155  */
156  if (RelationGetNumberOfBlocks(index) != 0)
157  elog(ERROR, "index \"%s\" already contains data",
158  RelationGetRelationName(index));
159 
160  /* no locking is needed */
161  buildstate.giststate = initGISTstate(index);
162 
163  /*
164  * Create a temporary memory context that is reset once for each tuple
165  * processed. (Note: we don't bother to make this a child of the
166  * giststate's scanCxt, so we have to delete it separately at the end.)
167  */
168  buildstate.giststate->tempCxt = createTempGistContext();
169 
170  /* initialize the root page */
171  buffer = gistNewBuffer(index);
173  page = BufferGetPage(buffer);
174 
176 
177  GISTInitBuffer(buffer, F_LEAF);
178 
179  MarkBufferDirty(buffer);
180 
181  if (RelationNeedsWAL(index))
182  {
183  XLogRecPtr recptr;
184 
185  XLogBeginInsert();
187 
188  recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_CREATE_INDEX);
189  PageSetLSN(page, recptr);
190  }
191  else
192  PageSetLSN(page, gistGetFakeLSN(heap));
193 
194  UnlockReleaseBuffer(buffer);
195 
197 
198  /* build the index */
199  buildstate.indtuples = 0;
200  buildstate.indtuplesSize = 0;
201 
202  /*
203  * Do the heap scan.
204  */
205  reltuples = IndexBuildHeapScan(heap, index, indexInfo, true,
206  gistBuildCallback, (void *) &buildstate);
207 
208  /*
209  * If buffering was used, flush out all the tuples that are still in the
210  * buffers.
211  */
212  if (buildstate.bufferingMode == GIST_BUFFERING_ACTIVE)
213  {
214  elog(DEBUG1, "all tuples processed, emptying buffers");
215  gistEmptyAllBuffers(&buildstate);
216  gistFreeBuildBuffers(buildstate.gfbb);
217  }
218 
219  /* okay, all heap tuples are indexed */
220  MemoryContextSwitchTo(oldcxt);
222 
223  freeGISTstate(buildstate.giststate);
224 
225  /*
226  * Return statistics
227  */
228  result = (IndexBuildResult *) palloc(sizeof(IndexBuildResult));
229 
230  result->heap_tuples = reltuples;
231  result->index_tuples = (double) buildstate.indtuples;
232 
233  return result;
234 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:200
#define DEBUG1
Definition: elog.h:25
int bufferingModeOffset
Definition: gist_private.h:377
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1445
MemoryContext createTempGistContext(void)
Definition: gist.c:110
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:213
#define END_CRIT_SECTION()
Definition: miscadmin.h:132
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define REGBUF_WILL_INIT
Definition: xloginsert.h:32
#define START_CRIT_SECTION()
Definition: miscadmin.h:130
#define XLOG_GIST_CREATE_INDEX
Definition: gistxlog.h:24
GistBufferingMode bufferingMode
Definition: gistbuild.c:74
XLogRecPtr gistGetFakeLSN(Relation rel)
Definition: gistutil.c:945
int64 indtuplesSize
Definition: gistbuild.c:62
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3315
#define ERROR
Definition: elog.h:43
int fillfactor
Definition: pgbench.c:112
int64 indtuples
Definition: gistbuild.c:61
MemoryContext tempCxt
Definition: gist_private.h:79
Size freespace
Definition: gistbuild.c:64
#define RelationGetRelationName(relation)
Definition: rel.h:433
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
#define GIST_DEFAULT_FILLFACTOR
Definition: gist_private.h:436
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
void freeGISTstate(GISTSTATE *giststate)
Definition: gist.c:1510
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
GISTSTATE * giststate
Definition: gistbuild.c:59
#define RelationGetNumberOfBlocks(reln)
Definition: bufmgr.h:199
GISTSTATE * initGISTstate(Relation index)
Definition: gist.c:1423
static void gistEmptyAllBuffers(GISTBuildState *buildstate)
Definition: gistbuild.c:992
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:671
Relation indexrel
Definition: gistbuild.c:58
#define RelationNeedsWAL(relation)
Definition: rel.h:502
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2588
void gistFreeBuildBuffers(GISTBuildBuffers *gfbb)
double IndexBuildHeapScan(Relation heapRelation, Relation indexRelation, IndexInfo *indexInfo, bool allow_sync, IndexBuildCallback callback, void *callback_state)
Definition: index.c:2169
void * palloc(Size size)
Definition: mcxt.c:891
static void gistBuildCallback(Relation index, HeapTuple htup, Datum *values, bool *isnull, bool tupleIsAlive, void *state)
Definition: gistbuild.c:458
#define F_LEAF
Definition: gist.h:42
GISTBuildBuffers * gfbb
Definition: gistbuild.c:71
#define GIST_ROOT_BLKNO
Definition: gist_private.h:249
void GISTInitBuffer(Buffer b, uint32 f)
Definition: gistutil.c:700
#define elog
Definition: elog.h:219
void XLogBeginInsert(void)
Definition: xloginsert.c:120
#define PageSetLSN(page, lsn)
Definition: bufpage.h:365
int Buffer
Definition: buf.h:23
Buffer gistNewBuffer(Relation r)
Definition: gistutil.c:761
bytea * rd_options
Definition: rel.h:152
Pointer Page
Definition: bufpage.h:74
double index_tuples
Definition: genam.h:33
double heap_tuples
Definition: genam.h:32
void gistbuildempty ( Relation  index)

Definition at line 121 of file gist.c.

References BUFFER_LOCK_EXCLUSIVE, END_CRIT_SECTION, F_LEAF, GISTInitBuffer(), INIT_FORKNUM, LockBuffer(), log_newpage_buffer(), MarkBufferDirty(), NULL, P_NEW, RBM_NORMAL, ReadBufferExtended(), START_CRIT_SECTION, and UnlockReleaseBuffer().

Referenced by gisthandler().

122 {
123  Buffer buffer;
124 
125  /* Initialize the root page */
128 
129  /* Initialize and xlog buffer */
131  GISTInitBuffer(buffer, F_LEAF);
132  MarkBufferDirty(buffer);
133  log_newpage_buffer(buffer, true);
135 
136  /* Unlock and release the buffer */
137  UnlockReleaseBuffer(buffer);
138 }
XLogRecPtr log_newpage_buffer(Buffer buffer, bool page_std)
Definition: xloginsert.c:1010
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1445
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition: bufmgr.c:640
#define END_CRIT_SECTION()
Definition: miscadmin.h:132
#define START_CRIT_SECTION()
Definition: miscadmin.h:130
#define P_NEW
Definition: bufmgr.h:82
#define BUFFER_LOCK_EXCLUSIVE
Definition: bufmgr.h:89
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3315
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3529
#define NULL
Definition: c.h:226
#define F_LEAF
Definition: gist.h:42
void GISTInitBuffer(Buffer b, uint32 f)
Definition: gistutil.c:700
int Buffer
Definition: buf.h:23
IndexBulkDeleteResult* gistbulkdelete ( IndexVacuumInfo info,
IndexBulkDeleteResult stats,
IndexBulkDeleteCallback  callback,
void *  callback_state 
)

Definition at line 139 of file gistvacuum.c.

References GistBDItem::blkno, BufferGetPage, callback(), END_CRIT_SECTION, ereport, errdetail(), errhint(), errmsg(), IndexBulkDeleteResult::estimated_count, FirstOffsetNumber, GIST_EXCLUSIVE, GIST_ROOT_BLKNO, GIST_SHARE, GIST_UNLOCK, gistcheckpage(), gistGetFakeLSN(), GistMarkTuplesDeleted, GistPageIsLeaf, GistTupleIsInvalid, gistXLogUpdate(), i, IndexVacuumInfo::index, InvalidBuffer, ItemPointerGetBlockNumber, LockBuffer(), LOG, MAIN_FORKNUM, MarkBufferDirty(), MaxOffsetNumber, GistBDItem::next, NULL, IndexBulkDeleteResult::num_index_tuples, OffsetNumberNext, PageGetItem, PageGetItemId, PageGetLSN, PageGetMaxOffsetNumber, PageIndexMultiDelete(), PageSetLSN, palloc(), palloc0(), GistBDItem::parentlsn, pfree(), pushStackIfSplited(), RBM_NORMAL, ReadBufferExtended(), RelationGetRelationName, RelationNeedsWAL, START_CRIT_SECTION, IndexVacuumInfo::strategy, IndexTupleData::t_tid, IndexBulkDeleteResult::tuples_removed, UnlockReleaseBuffer(), and vacuum_delay_point().

Referenced by gisthandler().

141 {
142  Relation rel = info->index;
143  GistBDItem *stack,
144  *ptr;
145 
146  /* first time through? */
147  if (stats == NULL)
149  /* we'll re-count the tuples each time */
150  stats->estimated_count = false;
151  stats->num_index_tuples = 0;
152 
153  stack = (GistBDItem *) palloc0(sizeof(GistBDItem));
154  stack->blkno = GIST_ROOT_BLKNO;
155 
156  while (stack)
157  {
158  Buffer buffer;
159  Page page;
160  OffsetNumber i,
161  maxoff;
162  IndexTuple idxtuple;
163  ItemId iid;
164 
165  buffer = ReadBufferExtended(rel, MAIN_FORKNUM, stack->blkno,
166  RBM_NORMAL, info->strategy);
167  LockBuffer(buffer, GIST_SHARE);
168  gistcheckpage(rel, buffer);
169  page = (Page) BufferGetPage(buffer);
170 
171  if (GistPageIsLeaf(page))
172  {
173  OffsetNumber todelete[MaxOffsetNumber];
174  int ntodelete = 0;
175 
176  LockBuffer(buffer, GIST_UNLOCK);
177  LockBuffer(buffer, GIST_EXCLUSIVE);
178 
179  page = (Page) BufferGetPage(buffer);
180  if (stack->blkno == GIST_ROOT_BLKNO && !GistPageIsLeaf(page))
181  {
182  /* only the root can become non-leaf during relock */
183  UnlockReleaseBuffer(buffer);
184  /* one more check */
185  continue;
186  }
187 
188  /*
189  * check for split proceeded after look at parent, we should check
190  * it after relock
191  */
192  pushStackIfSplited(page, stack);
193 
194  /*
195  * Remove deletable tuples from page
196  */
197 
198  maxoff = PageGetMaxOffsetNumber(page);
199 
200  for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
201  {
202  iid = PageGetItemId(page, i);
203  idxtuple = (IndexTuple) PageGetItem(page, iid);
204 
205  if (callback(&(idxtuple->t_tid), callback_state))
206  todelete[ntodelete++] = i;
207  else
208  stats->num_index_tuples += 1;
209  }
210 
211  stats->tuples_removed += ntodelete;
212 
213  if (ntodelete)
214  {
216 
217  MarkBufferDirty(buffer);
218 
219  PageIndexMultiDelete(page, todelete, ntodelete);
220  GistMarkTuplesDeleted(page);
221 
222  if (RelationNeedsWAL(rel))
223  {
224  XLogRecPtr recptr;
225 
226  recptr = gistXLogUpdate(buffer,
227  todelete, ntodelete,
228  NULL, 0, InvalidBuffer);
229  PageSetLSN(page, recptr);
230  }
231  else
232  PageSetLSN(page, gistGetFakeLSN(rel));
233 
235  }
236 
237  }
238  else
239  {
240  /* check for split proceeded after look at parent */
241  pushStackIfSplited(page, stack);
242 
243  maxoff = PageGetMaxOffsetNumber(page);
244 
245  for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
246  {
247  iid = PageGetItemId(page, i);
248  idxtuple = (IndexTuple) PageGetItem(page, iid);
249 
250  ptr = (GistBDItem *) palloc(sizeof(GistBDItem));
251  ptr->blkno = ItemPointerGetBlockNumber(&(idxtuple->t_tid));
252  ptr->parentlsn = PageGetLSN(page);
253  ptr->next = stack->next;
254  stack->next = ptr;
255 
256  if (GistTupleIsInvalid(idxtuple))
257  ereport(LOG,
258  (errmsg("index \"%s\" contains an inner tuple marked as invalid",
260  errdetail("This is caused by an incomplete page split at crash recovery before upgrading to PostgreSQL 9.1."),
261  errhint("Please REINDEX it.")));
262  }
263  }
264 
265  UnlockReleaseBuffer(buffer);
266 
267  ptr = stack->next;
268  pfree(stack);
269  stack = ptr;
270 
272  }
273 
274  return stats;
275 }
int errhint(const char *fmt,...)
Definition: elog.c:987
double tuples_removed
Definition: genam.h:77
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1445
#define MaxOffsetNumber
Definition: off.h:28
#define GistMarkTuplesDeleted(page)
Definition: gist.h:140
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition: bufmgr.c:640
ItemPointerData t_tid
Definition: itup.h:37
#define END_CRIT_SECTION()
Definition: miscadmin.h:132
BufferAccessStrategy strategy
Definition: genam.h:51
#define InvalidBuffer
Definition: buf.h:25
#define START_CRIT_SECTION()
Definition: miscadmin.h:130
Relation index
Definition: genam.h:46
#define GistTupleIsInvalid(itup)
Definition: gist_private.h:275
#define GIST_UNLOCK
Definition: gist_private.h:45
#define LOG
Definition: elog.h:26
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:354
GistNSN parentlsn
Definition: gistvacuum.c:104
XLogRecPtr gistGetFakeLSN(Relation rel)
Definition: gistutil.c:945
uint16 OffsetNumber
Definition: off.h:24
void pfree(void *pointer)
Definition: mcxt.c:992
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3315
static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)
Definition: test_ifaddrs.c:49
#define FirstOffsetNumber
Definition: off.h:27
IndexTupleData * IndexTuple
Definition: itup.h:53
int errdetail(const char *fmt,...)
Definition: elog.c:873
#define RelationGetRelationName(relation)
Definition: rel.h:433
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define ereport(elevel, rest)
Definition: elog.h:122
#define GistPageIsLeaf(page)
Definition: gist.h:132
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:232
void * palloc0(Size size)
Definition: mcxt.c:920
BlockNumber blkno
Definition: gistvacuum.c:105
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3529
XLogRecPtr gistXLogUpdate(Buffer buffer, OffsetNumber *todelete, int ntodelete, IndexTuple *itup, int ituplen, Buffer leftchildbuf)
Definition: gistxlog.c:457
#define NULL
Definition: c.h:226
uint64 XLogRecPtr
Definition: xlogdefs.h:21
void PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems)
Definition: bufpage.c:809
void gistcheckpage(Relation rel, Buffer buf)
Definition: gistutil.c:722
#define OffsetNumberNext(offsetNumber)
Definition: off.h:53
#define GIST_SHARE
Definition: gist_private.h:43
#define RelationNeedsWAL(relation)
Definition: rel.h:502
#define PageGetLSN(page)
Definition: bufpage.h:363
void * palloc(Size size)
Definition: mcxt.c:891
int errmsg(const char *fmt,...)
Definition: elog.c:797
int i
struct GistBDItem * next
Definition: gistvacuum.c:106
#define GIST_ROOT_BLKNO
Definition: gist_private.h:249
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:66
void vacuum_delay_point(void)
Definition: vacuum.c:1515
#define GIST_EXCLUSIVE
Definition: gist_private.h:44
#define PageSetLSN(page, lsn)
Definition: bufpage.h:365
double num_index_tuples
Definition: genam.h:76
int Buffer
Definition: buf.h:23
bool estimated_count
Definition: genam.h:75
#define PageGetItem(page, itemId)
Definition: bufpage.h:337
Pointer Page
Definition: bufpage.h:74
static void pushStackIfSplited(Page page, GistBDItem *stack)
Definition: gistvacuum.c:110
bool gistcanreturn ( Relation  index,
int  attno 
)

Definition at line 802 of file gistget.c.

References GIST_FETCH_PROC, index_getprocid(), and OidIsValid.

Referenced by gisthandler().

803 {
804  if (OidIsValid(index_getprocid(index, attno, GIST_FETCH_PROC)))
805  return true;
806  else
807  return false;
808 }
#define GIST_FETCH_PROC
Definition: gist.h:36
#define OidIsValid(objectId)
Definition: c.h:534
RegProcedure index_getprocid(Relation irel, AttrNumber attnum, uint16 procnum)
Definition: indexam.c:821
void gistcheckpage ( Relation  rel,
Buffer  buf 
)

Definition at line 722 of file gistutil.c.

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

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

723 {
724  Page page = BufferGetPage(buf);
725 
726  /*
727  * ReadBuffer verifies that every newly-read page passes
728  * PageHeaderIsValid, which means it either contains a reasonably sane
729  * page header or is all-zero. We have to defend against the all-zero
730  * case, however.
731  */
732  if (PageIsNew(page))
733  ereport(ERROR,
734  (errcode(ERRCODE_INDEX_CORRUPTED),
735  errmsg("index \"%s\" contains unexpected zero page at block %u",
738  errhint("Please REINDEX it.")));
739 
740  /*
741  * Additionally check that the special area looks sane.
742  */
743  if (PageGetSpecialSize(page) != MAXALIGN(sizeof(GISTPageOpaqueData)))
744  ereport(ERROR,
745  (errcode(ERRCODE_INDEX_CORRUPTED),
746  errmsg("index \"%s\" contains corrupted page at block %u",
749  errhint("Please REINDEX it.")));
750 }
int errhint(const char *fmt,...)
Definition: elog.c:987
int errcode(int sqlerrcode)
Definition: elog.c:575
#define ERROR
Definition: elog.h:43
static char * buf
Definition: pg_test_fsync.c:65
#define RelationGetRelationName(relation)
Definition: rel.h:433
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define ereport(elevel, rest)
Definition: elog.h:122
#define MAXALIGN(LEN)
Definition: c.h:584
#define PageGetSpecialSize(page)
Definition: bufpage.h:297
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2588
#define PageIsNew(page)
Definition: bufpage.h:226
int errmsg(const char *fmt,...)
Definition: elog.c:797
Pointer Page
Definition: bufpage.h:74
OffsetNumber gistchoose ( Relation  r,
Page  p,
IndexTuple  it,
GISTSTATE giststate 
)

Definition at line 371 of file gistutil.c.

References Assert, FALSE, FirstOffsetNumber, gistDeCompressAtt(), gistdentryinit(), GistPageIsLeaf, gistpenalty(), i, index_getattr, INDEX_MAX_KEYS, MAX_RANDOM_VALUE, tupleDesc::natts, NULL, OffsetNumberNext, PageGetItem, PageGetItemId, PageGetMaxOffsetNumber, random(), RelationData::rd_att, and GISTSTATE::tupdesc.

Referenced by gistdoinsert(), and gistProcessItup().

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

Definition at line 293 of file gistutil.c.

References FALSE, gistdentryinit(), i, index_getattr, tupleDesc::natts, RelationData::rd_att, and GISTSTATE::tupdesc.

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

295 {
296  int i;
297 
298  for (i = 0; i < r->rd_att->natts; i++)
299  {
300  Datum datum;
301 
302  datum = index_getattr(tuple, i + 1, giststate->tupdesc, &isnull[i]);
303  gistdentryinit(giststate, i, &attdata[i],
304  datum, r, p, o,
305  FALSE, isnull[i]);
306  }
307 }
TupleDesc tupdesc
Definition: gist_private.h:81
int natts
Definition: tupdesc.h:73
void gistdentryinit(GISTSTATE *giststate, int nkey, GISTENTRY *e, Datum k, Relation r, Page pg, OffsetNumber o, bool l, bool isNull)
Definition: gistutil.c:543
#define FALSE
Definition: c.h:218
uintptr_t Datum
Definition: postgres.h:374
TupleDesc rd_att
Definition: rel.h:114
#define index_getattr(tup, attnum, tupleDesc, isnull)
Definition: itup.h:100
int i
void gistdentryinit ( GISTSTATE giststate,
int  nkey,
GISTENTRY e,
Datum  k,
Relation  r,
Page  pg,
OffsetNumber  o,
bool  l,
bool  isNull 
)

Definition at line 543 of file gistutil.c.

References DatumGetPointer, GISTSTATE::decompressFn, FunctionCall1Coll(), gistentryinit, GISTENTRY::key, GISTENTRY::leafkey, GISTENTRY::offset, GISTENTRY::page, PointerGetDatum, GISTENTRY::rel, and GISTSTATE::supportCollation.

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

546 {
547  if (!isNull)
548  {
549  GISTENTRY *dep;
550 
551  gistentryinit(*e, k, r, pg, o, l);
552  dep = (GISTENTRY *)
554  giststate->supportCollation[nkey],
555  PointerGetDatum(e)));
556  /* decompressFn may just return the given pointer */
557  if (dep != e)
558  gistentryinit(*e, dep->key, dep->rel, dep->page, dep->offset,
559  dep->leafkey);
560  }
561  else
562  gistentryinit(*e, (Datum) 0, r, pg, o, l);
563 }
Relation rel
Definition: gist.h:124
Oid supportCollation[INDEX_MAX_KEYS]
Definition: gist_private.h:96
#define PointerGetDatum(X)
Definition: postgres.h:564
Page page
Definition: gist.h:125
Datum key
Definition: gist.h:123
FmgrInfo decompressFn[INDEX_MAX_KEYS]
Definition: gist_private.h:88
bool leafkey
Definition: gist.h:127
uintptr_t Datum
Definition: postgres.h:374
Datum FunctionCall1Coll(FmgrInfo *flinfo, Oid collation, Datum arg1)
Definition: fmgr.c:1286
#define gistentryinit(e, k, r, pg, o, l)
Definition: gist.h:169
#define DatumGetPointer(X)
Definition: postgres.h:557
OffsetNumber offset
Definition: gist.h:126
void gistdoinsert ( Relation  r,
IndexTuple  itup,
Size  freespace,
GISTSTATE GISTstate 
)

Definition at line 601 of file gist.c.

References Assert, GISTInsertStack::blkno, GISTInsertStack::buffer, BufferGetPage, GISTInsertStack::downlinkoffnum, ereport, errdetail(), errhint(), errmsg(), ERROR, GISTInsertState::freespace, GIST_EXCLUSIVE, GIST_ROOT_BLKNO, GIST_SHARE, GIST_UNLOCK, gistcheckpage(), gistchoose(), gistfixsplit(), GistFollowRight, gistgetadjusted(), gistinserttuple(), GistPageGetNSN, GistPageIsLeaf, GistTupleIsInvalid, InvalidOffsetNumber, ItemPointerGetBlockNumber, LockBuffer(), GISTInsertStack::lsn, NULL, GISTInsertStack::page, PageGetItem, PageGetItemId, PageGetLSN, palloc0(), GISTInsertStack::parent, GISTInsertState::r, ReadBuffer(), RelationGetRelationName, RelationNeedsWAL, ReleaseBuffer(), GISTInsertState::stack, IndexTupleData::t_tid, UnlockReleaseBuffer(), and XLogRecPtrIsInvalid.

Referenced by gistBuildCallback(), and gistinsert().

602 {
603  ItemId iid;
604  IndexTuple idxtuple;
605  GISTInsertStack firststack;
606  GISTInsertStack *stack;
608  bool xlocked = false;
609 
610  memset(&state, 0, sizeof(GISTInsertState));
611  state.freespace = freespace;
612  state.r = r;
613 
614  /* Start from the root */
615  firststack.blkno = GIST_ROOT_BLKNO;
616  firststack.lsn = 0;
617  firststack.parent = NULL;
618  firststack.downlinkoffnum = InvalidOffsetNumber;
619  state.stack = stack = &firststack;
620 
621  /*
622  * Walk down along the path of smallest penalty, updating the parent
623  * pointers with the key we're inserting as we go. If we crash in the
624  * middle, the tree is consistent, although the possible parent updates
625  * were a waste.
626  */
627  for (;;)
628  {
629  if (XLogRecPtrIsInvalid(stack->lsn))
630  stack->buffer = ReadBuffer(state.r, stack->blkno);
631 
632  /*
633  * Be optimistic and grab shared lock first. Swap it for an exclusive
634  * lock later if we need to update the page.
635  */
636  if (!xlocked)
637  {
638  LockBuffer(stack->buffer, GIST_SHARE);
639  gistcheckpage(state.r, stack->buffer);
640  }
641 
642  stack->page = (Page) BufferGetPage(stack->buffer);
643  stack->lsn = PageGetLSN(stack->page);
644  Assert(!RelationNeedsWAL(state.r) || !XLogRecPtrIsInvalid(stack->lsn));
645 
646  /*
647  * If this page was split but the downlink was never inserted to the
648  * parent because the inserting backend crashed before doing that, fix
649  * that now.
650  */
651  if (GistFollowRight(stack->page))
652  {
653  if (!xlocked)
654  {
655  LockBuffer(stack->buffer, GIST_UNLOCK);
657  xlocked = true;
658  /* someone might've completed the split when we unlocked */
659  if (!GistFollowRight(stack->page))
660  continue;
661  }
662  gistfixsplit(&state, giststate);
663 
664  UnlockReleaseBuffer(stack->buffer);
665  xlocked = false;
666  state.stack = stack = stack->parent;
667  continue;
668  }
669 
670  if (stack->blkno != GIST_ROOT_BLKNO &&
671  stack->parent->lsn < GistPageGetNSN(stack->page))
672  {
673  /*
674  * Concurrent split detected. There's no guarantee that the
675  * downlink for this page is consistent with the tuple we're
676  * inserting anymore, so go back to parent and rechoose the best
677  * child.
678  */
679  UnlockReleaseBuffer(stack->buffer);
680  xlocked = false;
681  state.stack = stack = stack->parent;
682  continue;
683  }
684 
685  if (!GistPageIsLeaf(stack->page))
686  {
687  /*
688  * This is an internal page so continue to walk down the tree.
689  * Find the child node that has the minimum insertion penalty.
690  */
691  BlockNumber childblkno;
692  IndexTuple newtup;
693  GISTInsertStack *item;
694  OffsetNumber downlinkoffnum;
695 
696  downlinkoffnum = gistchoose(state.r, stack->page, itup, giststate);
697  iid = PageGetItemId(stack->page, downlinkoffnum);
698  idxtuple = (IndexTuple) PageGetItem(stack->page, iid);
699  childblkno = ItemPointerGetBlockNumber(&(idxtuple->t_tid));
700 
701  /*
702  * Check that it's not a leftover invalid tuple from pre-9.1
703  */
704  if (GistTupleIsInvalid(idxtuple))
705  ereport(ERROR,
706  (errmsg("index \"%s\" contains an inner tuple marked as invalid",
708  errdetail("This is caused by an incomplete page split at crash recovery before upgrading to PostgreSQL 9.1."),
709  errhint("Please REINDEX it.")));
710 
711  /*
712  * Check that the key representing the target child node is
713  * consistent with the key we're inserting. Update it if it's not.
714  */
715  newtup = gistgetadjusted(state.r, idxtuple, itup, giststate);
716  if (newtup)
717  {
718  /*
719  * Swap shared lock for an exclusive one. Beware, the page may
720  * change while we unlock/lock the page...
721  */
722  if (!xlocked)
723  {
724  LockBuffer(stack->buffer, GIST_UNLOCK);
726  xlocked = true;
727  stack->page = (Page) BufferGetPage(stack->buffer);
728 
729  if (PageGetLSN(stack->page) != stack->lsn)
730  {
731  /* the page was changed while we unlocked it, retry */
732  continue;
733  }
734  }
735 
736  /*
737  * Update the tuple.
738  *
739  * We still hold the lock after gistinserttuple(), but it
740  * might have to split the page to make the updated tuple fit.
741  * In that case the updated tuple might migrate to the other
742  * half of the split, so we have to go back to the parent and
743  * descend back to the half that's a better fit for the new
744  * tuple.
745  */
746  if (gistinserttuple(&state, stack, giststate, newtup,
747  downlinkoffnum))
748  {
749  /*
750  * If this was a root split, the root page continues to be
751  * the parent and the updated tuple went to one of the
752  * child pages, so we just need to retry from the root
753  * page.
754  */
755  if (stack->blkno != GIST_ROOT_BLKNO)
756  {
757  UnlockReleaseBuffer(stack->buffer);
758  xlocked = false;
759  state.stack = stack = stack->parent;
760  }
761  continue;
762  }
763  }
764  LockBuffer(stack->buffer, GIST_UNLOCK);
765  xlocked = false;
766 
767  /* descend to the chosen child */
768  item = (GISTInsertStack *) palloc0(sizeof(GISTInsertStack));
769  item->blkno = childblkno;
770  item->parent = stack;
771  item->downlinkoffnum = downlinkoffnum;
772  state.stack = stack = item;
773  }
774  else
775  {
776  /*
777  * Leaf page. Insert the new key. We've already updated all the
778  * parents on the way down, but we might have to split the page if
779  * it doesn't fit. gistinserthere() will take care of that.
780  */
781 
782  /*
783  * Swap shared lock for an exclusive one. Be careful, the page may
784  * change while we unlock/lock the page...
785  */
786  if (!xlocked)
787  {
788  LockBuffer(stack->buffer, GIST_UNLOCK);
790  xlocked = true;
791  stack->page = (Page) BufferGetPage(stack->buffer);
792  stack->lsn = PageGetLSN(stack->page);
793 
794  if (stack->blkno == GIST_ROOT_BLKNO)
795  {
796  /*
797  * the only page that can become inner instead of leaf is
798  * the root page, so for root we should recheck it
799  */
800  if (!GistPageIsLeaf(stack->page))
801  {
802  /*
803  * very rare situation: during unlock/lock index with
804  * number of pages = 1 was increased
805  */
806  LockBuffer(stack->buffer, GIST_UNLOCK);
807  xlocked = false;
808  continue;
809  }
810 
811  /*
812  * we don't need to check root split, because checking
813  * leaf/inner is enough to recognize split for root
814  */
815  }
816  else if (GistFollowRight(stack->page) ||
817  stack->parent->lsn < GistPageGetNSN(stack->page))
818  {
819  /*
820  * The page was split while we momentarily unlocked the
821  * page. Go back to parent.
822  */
823  UnlockReleaseBuffer(stack->buffer);
824  xlocked = false;
825  state.stack = stack = stack->parent;
826  continue;
827  }
828  }
829 
830  /* now state.stack->(page, buffer and blkno) points to leaf page */
831 
832  gistinserttuple(&state, stack, giststate, itup,
834  LockBuffer(stack->buffer, GIST_UNLOCK);
835 
836  /* Release any pins we might still hold before exiting */
837  for (; stack; stack = stack->parent)
838  ReleaseBuffer(stack->buffer);
839  break;
840  }
841  }
842 }
#define GistFollowRight(page)
Definition: gist.h:147
BlockNumber blkno
Definition: gist_private.h:206
#define GistPageGetNSN(page)
Definition: gist.h:151
static bool gistinserttuple(GISTInsertState *state, GISTInsertStack *stack, GISTSTATE *giststate, IndexTuple tuple, OffsetNumber oldoffnum)
Definition: gist.c:1172
int errhint(const char *fmt,...)
Definition: elog.c:987
static void gistfixsplit(GISTInsertState *state, GISTSTATE *giststate)
Definition: gist.c:1113
ItemPointerData t_tid
Definition: itup.h:37
#define GistTupleIsInvalid(itup)
Definition: gist_private.h:275
#define GIST_UNLOCK
Definition: gist_private.h:45
uint32 BlockNumber
Definition: block.h:31
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3292
IndexTuple gistgetadjusted(Relation r, IndexTuple oldtup, IndexTuple addtup, GISTSTATE *giststate)
Definition: gistutil.c:313
uint16 OffsetNumber
Definition: off.h:24
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3315
#define ERROR
Definition: elog.h:43
GISTInsertStack * stack
Definition: gist_private.h:245
IndexTupleData * IndexTuple
Definition: itup.h:53
int errdetail(const char *fmt,...)
Definition: elog.c:873
#define RelationGetRelationName(relation)
Definition: rel.h:433
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define ereport(elevel, rest)
Definition: elog.h:122
OffsetNumber gistchoose(Relation r, Page p, IndexTuple it, GISTSTATE *giststate)
Definition: gistutil.c:371
#define GistPageIsLeaf(page)
Definition: gist.h:132
#define XLogRecPtrIsInvalid(r)
Definition: xlogdefs.h:29
OffsetNumber downlinkoffnum
Definition: gist_private.h:217
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:232
void * palloc0(Size size)
Definition: mcxt.c:920
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3529
#define InvalidOffsetNumber
Definition: off.h:26
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
Definition: regguts.h:298
void gistcheckpage(Relation rel, Buffer buf)
Definition: gistutil.c:722
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:594
#define GIST_SHARE
Definition: gist_private.h:43
#define RelationNeedsWAL(relation)
Definition: rel.h:502
#define PageGetLSN(page)
Definition: bufpage.h:363
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define GIST_ROOT_BLKNO
Definition: gist_private.h:249
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:66
#define GIST_EXCLUSIVE
Definition: gist_private.h:44
struct GISTInsertStack * parent
Definition: gist_private.h:220
#define PageGetItem(page, itemId)
Definition: bufpage.h:337
Pointer Page
Definition: bufpage.h:74
IndexTuple* gistextractpage ( Page  page,
int *  len 
)

Definition at line 93 of file gistutil.c.

References FirstOffsetNumber, i, OffsetNumberNext, PageGetItem, PageGetItemId, PageGetMaxOffsetNumber, and palloc().

Referenced by gistplacetopage().

94 {
96  maxoff;
97  IndexTuple *itvec;
98 
99  maxoff = PageGetMaxOffsetNumber(page);
100  *len = maxoff;
101  itvec = palloc(sizeof(IndexTuple) * maxoff);
102  for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
103  itvec[i - FirstOffsetNumber] = (IndexTuple) PageGetItem(page, PageGetItemId(page, i));
104 
105  return itvec;
106 }
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:354
uint16 OffsetNumber
Definition: off.h:24
#define FirstOffsetNumber
Definition: off.h:27
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:232
#define OffsetNumberNext(offsetNumber)
Definition: off.h:53
void * palloc(Size size)
Definition: mcxt.c:891
int i
#define PageGetItem(page, itemId)
Definition: bufpage.h:337
IndexTuple gistFetchTuple ( GISTSTATE giststate,
Relation  r,
IndexTuple  tuple 
)

Definition at line 630 of file gistutil.c.

References fetchatt, GISTSTATE::fetchFn, GISTSTATE::fetchTupdesc, FmgrInfo::fn_oid, gistFetchAtt(), i, index_form_tuple(), index_getattr, INDEX_MAX_KEYS, InvalidOid, MemoryContextSwitchTo(), tupleDesc::natts, RelationData::rd_att, GISTSTATE::tempCxt, and GISTSTATE::tupdesc.

Referenced by gistScanPage().

631 {
632  MemoryContext oldcxt = MemoryContextSwitchTo(giststate->tempCxt);
634  bool isnull[INDEX_MAX_KEYS];
635  int i;
636 
637  for (i = 0; i < r->rd_att->natts; i++)
638  {
639  Datum datum;
640 
641  datum = index_getattr(tuple, i + 1, giststate->tupdesc, &isnull[i]);
642 
643  if (giststate->fetchFn[i].fn_oid != InvalidOid)
644  {
645  if (!isnull[i])
646  fetchatt[i] = gistFetchAtt(giststate, i, datum, r);
647  else
648  fetchatt[i] = (Datum) 0;
649  }
650  else
651  {
652  /*
653  * Index-only scans not supported for this column. Since the
654  * planner chose an index-only scan anyway, it is not interested
655  * in this column, and we can replace it with a NULL.
656  */
657  isnull[i] = true;
658  fetchatt[i] = (Datum) 0;
659  }
660  }
661  MemoryContextSwitchTo(oldcxt);
662 
663  return index_form_tuple(giststate->fetchTupdesc, fetchatt, isnull);
664 }
TupleDesc tupdesc
Definition: gist_private.h:81
static Datum gistFetchAtt(GISTSTATE *giststate, int nkey, Datum k, Relation r)
Definition: gistutil.c:609
FmgrInfo fetchFn[INDEX_MAX_KEYS]
Definition: gist_private.h:93
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int natts
Definition: tupdesc.h:73
#define fetchatt(A, T)
Definition: tupmacs.h:37
IndexTuple index_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: indextuple.c:37
MemoryContext tempCxt
Definition: gist_private.h:79
uintptr_t Datum
Definition: postgres.h:374
TupleDesc rd_att
Definition: rel.h:114
#define InvalidOid
Definition: postgres_ext.h:36
Oid fn_oid
Definition: fmgr.h:56
TupleDesc fetchTupdesc
Definition: gist_private.h:82
#define INDEX_MAX_KEYS
#define index_getattr(tup, attnum, tupleDesc, isnull)
Definition: itup.h:100
int i
void gistfillbuffer ( Page  page,
IndexTuple itup,
int  len,
OffsetNumber  off 
)

Definition at line 32 of file gistutil.c.

References elog, ERROR, FirstOffsetNumber, i, IndexTupleSize, InvalidOffsetNumber, OffsetNumberNext, PageAddItem, PageGetMaxOffsetNumber, and PageIsEmpty.

Referenced by gistplacetopage(), and gistRedoPageSplitRecord().

33 {
35  int i;
36 
37  if (off == InvalidOffsetNumber)
38  off = (PageIsEmpty(page)) ? FirstOffsetNumber :
40 
41  for (i = 0; i < len; i++)
42  {
43  Size sz = IndexTupleSize(itup[i]);
44 
45  l = PageAddItem(page, (Item) itup[i], sz, off, false, false);
46  if (l == InvalidOffsetNumber)
47  elog(ERROR, "failed to add item to GiST index page, item %d out of %d, size %d bytes",
48  i, len, (int) sz);
49  off++;
50  }
51 }
#define PageIsEmpty(page)
Definition: bufpage.h:219
Pointer Item
Definition: item.h:17
#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap)
Definition: bufpage.h:413
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:354
uint16 OffsetNumber
Definition: off.h:24
#define ERROR
Definition: elog.h:43
#define FirstOffsetNumber
Definition: off.h:27
#define InvalidOffsetNumber
Definition: off.h:26
#define OffsetNumberNext(offsetNumber)
Definition: off.h:53
size_t Size
Definition: c.h:353
int i
#define elog
Definition: elog.h:219
#define IndexTupleSize(itup)
Definition: itup.h:70
IndexTupleData* gistfillitupvec ( IndexTuple vec,
int  veclen,
int *  memlen 
)

Definition at line 125 of file gistutil.c.

References i, IndexTupleSize, and palloc().

Referenced by gistplacetopage(), and gistSplit().

126 {
127  char *ptr,
128  *ret;
129  int i;
130 
131  *memlen = 0;
132 
133  for (i = 0; i < veclen; i++)
134  *memlen += IndexTupleSize(vec[i]);
135 
136  ptr = ret = palloc(*memlen);
137 
138  for (i = 0; i < veclen; i++)
139  {
140  memcpy(ptr, vec[i], IndexTupleSize(vec[i]));
141  ptr += IndexTupleSize(vec[i]);
142  }
143 
144  return (IndexTupleData *) ret;
145 }
void * palloc(Size size)
Definition: mcxt.c:891
int i
#define IndexTupleSize(itup)
Definition: itup.h:70
bool gistfitpage ( IndexTuple itvec,
int  len 
)

Definition at line 77 of file gistutil.c.

References GiSTPageSize, i, and IndexTupleSize.

Referenced by gistSplit().

78 {
79  int i;
80  Size size = 0;
81 
82  for (i = 0; i < len; i++)
83  size += IndexTupleSize(itvec[i]) + sizeof(ItemIdData);
84 
85  /* TODO: Consider fillfactor */
86  return (size <= GiSTPageSize);
87 }
struct ItemIdData ItemIdData
#define GiSTPageSize
Definition: gist_private.h:432
size_t Size
Definition: c.h:353
int i
#define IndexTupleSize(itup)
Definition: itup.h:70
IndexTuple gistFormTuple ( GISTSTATE giststate,
Relation  r,
Datum attdata,
bool isnull,
bool  isleaf 
)
void gistFreeBuildBuffers ( GISTBuildBuffers gfbb)

Definition at line 511 of file gistbuildbuffers.c.

References BufFileClose(), and GISTBuildBuffers::pfile.

Referenced by gistbuild().

512 {
513  /* Close buffers file. */
514  BufFileClose(gfbb->pfile);
515 
516  /* All other things will be freed on memory context release */
517 }
void BufFileClose(BufFile *file)
Definition: buffile.c:202
IndexTuple gistgetadjusted ( Relation  r,
IndexTuple  oldtup,
IndexTuple  addtup,
GISTSTATE giststate 
)

Definition at line 313 of file gistutil.c.

References FALSE, gistDeCompressAtt(), gistFormTuple(), gistKeyIsEQ(), gistMakeUnionKey(), i, INDEX_MAX_KEYS, tupleDesc::natts, NULL, RelationData::rd_att, and IndexTupleData::t_tid.

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

314 {
315  bool neednew = FALSE;
316  GISTENTRY oldentries[INDEX_MAX_KEYS],
317  addentries[INDEX_MAX_KEYS];
318  bool oldisnull[INDEX_MAX_KEYS],
319  addisnull[INDEX_MAX_KEYS];
320  Datum attr[INDEX_MAX_KEYS];
321  bool isnull[INDEX_MAX_KEYS];
322  IndexTuple newtup = NULL;
323  int i;
324 
325  gistDeCompressAtt(giststate, r, oldtup, NULL,
326  (OffsetNumber) 0, oldentries, oldisnull);
327 
328  gistDeCompressAtt(giststate, r, addtup, NULL,
329  (OffsetNumber) 0, addentries, addisnull);
330 
331  for (i = 0; i < r->rd_att->natts; i++)
332  {
333  gistMakeUnionKey(giststate, i,
334  oldentries + i, oldisnull[i],
335  addentries + i, addisnull[i],
336  attr + i, isnull + i);
337 
338  if (neednew)
339  /* we already need new key, so we can skip check */
340  continue;
341 
342  if (isnull[i])
343  /* union of key may be NULL if and only if both keys are NULL */
344  continue;
345 
346  if (!addisnull[i])
347  {
348  if (oldisnull[i] ||
349  !gistKeyIsEQ(giststate, i, oldentries[i].key, attr[i]))
350  neednew = true;
351  }
352  }
353 
354  if (neednew)
355  {
356  /* need to update key */
357  newtup = gistFormTuple(giststate, r, attr, isnull, false);
358  newtup->t_tid = oldtup->t_tid;
359  }
360 
361  return newtup;
362 }
void gistDeCompressAtt(GISTSTATE *giststate, Relation r, IndexTuple tuple, Page p, OffsetNumber o, GISTENTRY *attdata, bool *isnull)
Definition: gistutil.c:293
ItemPointerData t_tid
Definition: itup.h:37
int natts
Definition: tupdesc.h:73
bool gistKeyIsEQ(GISTSTATE *giststate, int attno, Datum a, Datum b)
Definition: gistutil.c:278
uint16 OffsetNumber
Definition: off.h:24
#define FALSE
Definition: c.h:218
uintptr_t Datum
Definition: postgres.h:374
TupleDesc rd_att
Definition: rel.h:114
#define NULL
Definition: c.h:226
void gistMakeUnionKey(GISTSTATE *giststate, int attno, GISTENTRY *entry1, bool isnull1, GISTENTRY *entry2, bool isnull2, Datum *dst, bool *dstisnull)
Definition: gistutil.c:230
#define INDEX_MAX_KEYS
int i
IndexTuple gistFormTuple(GISTSTATE *giststate, Relation r, Datum attdata[], bool isnull[], bool isleaf)
Definition: gistutil.c:566
int64 gistgetbitmap ( IndexScanDesc  scan,
TIDBitmap tbm 
)

Definition at line 755 of file gistget.c.

References CHECK_FOR_INTERRUPTS, GISTScanOpaqueData::curPageData, GISTSearchItem::distances, getNextGISTSearchItem(), GIST_ROOT_BLKNO, gistScanPage(), IndexScanDescData::indexRelation, MemoryContextReset(), GISTScanOpaqueData::nPageData, NULL, IndexScanDescData::opaque, GISTScanOpaqueData::pageDataCxt, pfree(), pgstat_count_index_scan, and GISTScanOpaqueData::qual_ok.

Referenced by gisthandler().

756 {
757  GISTScanOpaque so = (GISTScanOpaque) scan->opaque;
758  int64 ntids = 0;
759  GISTSearchItem fakeItem;
760 
761  if (!so->qual_ok)
762  return 0;
763 
765 
766  /* Begin the scan by processing the root page */
767  so->curPageData = so->nPageData = 0;
768  if (so->pageDataCxt)
770 
771  fakeItem.blkno = GIST_ROOT_BLKNO;
772  memset(&fakeItem.data.parentlsn, 0, sizeof(GistNSN));
773  gistScanPage(scan, &fakeItem, NULL, tbm, &ntids);
774 
775  /*
776  * While scanning a leaf page, ItemPointers of matching heap tuples will
777  * be stored directly into tbm, so we don't need to deal with them here.
778  */
779  for (;;)
780  {
782 
783  if (!item)
784  break;
785 
787 
788  gistScanPage(scan, item, item->distances, tbm, &ntids);
789 
790  pfree(item);
791  }
792 
793  return ntids;
794 }
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:135
MemoryContext pageDataCxt
Definition: gist_private.h:173
Relation indexRelation
Definition: relscan.h:89
double distances[FLEXIBLE_ARRAY_MEMBER]
Definition: gist_private.h:139
void pfree(void *pointer)
Definition: mcxt.c:992
static void gistScanPage(IndexScanDesc scan, GISTSearchItem *pageItem, double *myDistances, TIDBitmap *tbm, int64 *ntids)
Definition: gistget.c:322
GISTScanOpaqueData * GISTScanOpaque
Definition: gist_private.h:177
#define pgstat_count_index_scan(rel)
Definition: pgstat.h:1155
OffsetNumber nPageData
Definition: gist_private.h:171
static GISTSearchItem * getNextGISTSearchItem(GISTScanOpaque so)
Definition: gistget.c:515
#define NULL
Definition: c.h:226
OffsetNumber curPageData
Definition: gist_private.h:172
XLogRecPtr GistNSN
Definition: gist.h:50
#define GIST_ROOT_BLKNO
Definition: gist_private.h:249
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:97
XLogRecPtr gistGetFakeLSN ( Relation  rel)

Definition at line 945 of file gistutil.c.

References Assert, GetFakeLSNForUnloggedRel(), RelationData::rd_rel, RELPERSISTENCE_TEMP, and RELPERSISTENCE_UNLOGGED.

Referenced by gistbuild(), gistbulkdelete(), gistplacetopage(), and gistvacuumpage().

946 {
947  static XLogRecPtr counter = 1;
948 
949  if (rel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
950  {
951  /*
952  * Temporary relations are only accessible in our session, so a simple
953  * backend-local counter will do.
954  */
955  return counter++;
956  }
957  else
958  {
959  /*
960  * Unlogged relations are accessible from other backends, and survive
961  * (clean) restarts. GetFakeLSNForUnloggedRel() handles that for us.
962  */
963  Assert(rel->rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED);
964  return GetFakeLSNForUnloggedRel();
965  }
966 }
#define RELPERSISTENCE_UNLOGGED
Definition: pg_class.h:171
Form_pg_class rd_rel
Definition: rel.h:113
XLogRecPtr GetFakeLSNForUnloggedRel(void)
Definition: xlog.c:4687
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:671
#define RELPERSISTENCE_TEMP
Definition: pg_class.h:172
GISTNodeBuffer* gistGetNodeBuffer ( GISTBuildBuffers gfbb,
GISTSTATE giststate,
BlockNumber  blkno,
int  level 
)

Definition at line 118 of file gistbuildbuffers.c.

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

Referenced by gistProcessItup(), and gistRelocateBuildBuffersOnSplit().

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

Definition at line 625 of file gistget.c.

References GISTSearchItem::blkno, CHECK_FOR_INTERRUPTS, GISTScanOpaqueData::curBlkno, GISTScanOpaqueData::curPageData, GISTSearchItem::data, GISTSearchItem::distances, elog, ERROR, GISTScanOpaqueData::firstCall, ForwardScanDirection, GISTSearchHeapItem::ftup, getNextGISTSearchItem(), getNextNearest(), GIST_ROOT_BLKNO, gistkillitems(), gistScanPage(), GISTScanOpaqueData::giststate, GISTSearchHeapItem::heapPtr, IndexScanDescData::indexRelation, InvalidBlockNumber, IndexScanDescData::kill_prior_tuple, GISTScanOpaqueData::killedItems, MaxIndexTuplesPerPage, MemoryContextReset(), MemoryContextSwitchTo(), GISTScanOpaqueData::nPageData, NULL, IndexScanDescData::numberOfOrderBys, GISTScanOpaqueData::numKilled, GISTSearchHeapItem::offnum, IndexScanDescData::opaque, GISTScanOpaqueData::pageData, GISTScanOpaqueData::pageDataCxt, palloc(), GISTSearchItem::parentlsn, pfree(), pgstat_count_index_scan, GISTScanOpaqueData::qual_ok, GISTSearchHeapItem::recheck, GISTSTATE::scanCxt, HeapTupleData::t_self, IndexScanDescData::xs_ctup, IndexScanDescData::xs_itup, IndexScanDescData::xs_recheck, and IndexScanDescData::xs_want_itup.

Referenced by gisthandler().

626 {
627  GISTScanOpaque so = (GISTScanOpaque) scan->opaque;
628 
629  if (dir != ForwardScanDirection)
630  elog(ERROR, "GiST only supports forward scan direction");
631 
632  if (!so->qual_ok)
633  return false;
634 
635  if (so->firstCall)
636  {
637  /* Begin the scan by processing the root page */
638  GISTSearchItem fakeItem;
639 
641 
642  so->firstCall = false;
643  so->curPageData = so->nPageData = 0;
644  if (so->pageDataCxt)
646 
647  fakeItem.blkno = GIST_ROOT_BLKNO;
648  memset(&fakeItem.data.parentlsn, 0, sizeof(GistNSN));
649  gistScanPage(scan, &fakeItem, NULL, NULL, NULL);
650  }
651 
652  if (scan->numberOfOrderBys > 0)
653  {
654  /* Must fetch tuples in strict distance order */
655  return getNextNearest(scan);
656  }
657  else
658  {
659  /* Fetch tuples index-page-at-a-time */
660  for (;;)
661  {
662  if (so->curPageData < so->nPageData)
663  {
664  if (scan->kill_prior_tuple && so->curPageData > 0)
665  {
666 
667  if (so->killedItems == NULL)
668  {
669  MemoryContext oldCxt =
671 
672  so->killedItems =
674  * sizeof(OffsetNumber));
675 
676  MemoryContextSwitchTo(oldCxt);
677  }
679  so->killedItems[so->numKilled++] =
680  so->pageData[so->curPageData - 1].offnum;
681  }
682  /* continuing to return tuples from a leaf page */
683  scan->xs_ctup.t_self = so->pageData[so->curPageData].heapPtr;
684  scan->xs_recheck = so->pageData[so->curPageData].recheck;
685 
686  /* in an index-only scan, also return the reconstructed tuple */
687  if (scan->xs_want_itup)
688  scan->xs_itup = so->pageData[so->curPageData].ftup;
689 
690  so->curPageData++;
691 
692  return true;
693  }
694 
695  /*
696  * Check the last returned tuple and add it to killitems if
697  * necessary
698  */
699  if (scan->kill_prior_tuple
700  && so->curPageData > 0
701  && so->curPageData == so->nPageData)
702  {
703 
704  if (so->killedItems == NULL)
705  {
706  MemoryContext oldCxt =
708 
709  so->killedItems =
711  * sizeof(OffsetNumber));
712 
713  MemoryContextSwitchTo(oldCxt);
714  }
716  so->killedItems[so->numKilled++] =
717  so->pageData[so->curPageData - 1].offnum;
718  }
719  /* find and process the next index page */
720  do
721  {
722  GISTSearchItem *item;
723 
724  if ((so->curBlkno != InvalidBlockNumber) && (so->numKilled > 0))
725  gistkillitems(scan);
726 
727  item = getNextGISTSearchItem(so);
728 
729  if (!item)
730  return false;
731 
733 
734  /* save current item BlockNumber for next gistkillitems() call */
735  so->curBlkno = item->blkno;
736 
737  /*
738  * While scanning a leaf page, ItemPointers of matching heap
739  * tuples are stored in so->pageData. If there are any on
740  * this page, we fall out of the inner "do" and loop around to
741  * return them.
742  */
743  gistScanPage(scan, item, item->distances, NULL, NULL);
744 
745  pfree(item);
746  } while (so->nPageData == 0);
747  }
748  }
749 }
BlockNumber blkno
Definition: gist_private.h:132
OffsetNumber * killedItems
Definition: gist_private.h:164
IndexTuple xs_itup
Definition: relscan.h:108
BlockNumber curBlkno
Definition: gist_private.h:166
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:135
MemoryContext pageDataCxt
Definition: gist_private.h:173
Relation indexRelation
Definition: relscan.h:89
uint16 OffsetNumber
Definition: off.h:24
GISTSTATE * giststate
Definition: gist_private.h:152
double distances[FLEXIBLE_ARRAY_MEMBER]
Definition: gist_private.h:139
void pfree(void *pointer)
Definition: mcxt.c:992
#define ERROR
Definition: elog.h:43
static void gistScanPage(IndexScanDesc scan, GISTSearchItem *pageItem, double *myDistances, TIDBitmap *tbm, int64 *ntids)
Definition: gistget.c:322
ItemPointerData t_self
Definition: htup.h:65
GISTScanOpaqueData * GISTScanOpaque
Definition: gist_private.h:177
#define pgstat_count_index_scan(rel)
Definition: pgstat.h:1155
OffsetNumber nPageData
Definition: gist_private.h:171
static GISTSearchItem * getNextGISTSearchItem(GISTScanOpaque so)
Definition: gistget.c:515
union GISTSearchItem::@36 data
bool xs_want_itup
Definition: relscan.h:95
ItemPointerData heapPtr
Definition: gist_private.h:119
#define NULL
Definition: c.h:226
static bool getNextNearest(IndexScanDesc scan)
Definition: gistget.c:537
HeapTupleData xs_ctup
Definition: relscan.h:112
GISTSearchHeapItem pageData[BLCKSZ/sizeof(IndexTupleData)]
Definition: gist_private.h:170
#define InvalidBlockNumber
Definition: block.h:33
OffsetNumber curPageData
Definition: gist_private.h:172
XLogRecPtr GistNSN
Definition: gist.h:50
static void gistkillitems(IndexScanDesc scan)
Definition: gistget.c:37
#define MaxIndexTuplesPerPage
Definition: itup.h:137
void * palloc(Size size)
Definition: mcxt.c:891
OffsetNumber offnum
Definition: gist_private.h:124
#define GIST_ROOT_BLKNO
Definition: gist_private.h:249
bool kill_prior_tuple
Definition: relscan.h:99
MemoryContext scanCxt
Definition: gist_private.h:78
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:97
int numberOfOrderBys
Definition: relscan.h:92
#define elog
Definition: elog.h:219
GistNSN parentlsn
Definition: gist_private.h:135
void GISTInitBuffer ( Buffer  b,
uint32  f 
)

Definition at line 700 of file gistutil.c.

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

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

701 {
702  GISTPageOpaque opaque;
703  Page page;
704  Size pageSize;
705 
706  pageSize = BufferGetPageSize(b);
707  page = BufferGetPage(b);
708  PageInit(page, pageSize, sizeof(GISTPageOpaqueData));
709 
710  opaque = GistPageGetOpaque(page);
711  /* page was already zeroed by PageInit, so this is not needed: */
712  /* memset(&(opaque->nsn), 0, sizeof(GistNSN)); */
713  opaque->rightlink = InvalidBlockNumber;
714  opaque->flags = f;
715  opaque->gist_page_id = GIST_PAGE_ID;
716 }
uint16 gist_page_id
Definition: gist.h:63
uint16 flags
Definition: gist.h:62
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define BufferGetPageSize(buffer)
Definition: bufmgr.h:147
#define GistPageGetOpaque(page)
Definition: gist.h:130
size_t Size
Definition: c.h:353
#define InvalidBlockNumber
Definition: block.h:33
BlockNumber rightlink
Definition: gist.h:61
#define GIST_PAGE_ID
Definition: gist.h:74
Pointer Page
Definition: bufpage.h:74
void PageInit(Page page, Size pageSize, Size specialSize)
Definition: bufpage.c:41
GISTBuildBuffers* gistInitBuildBuffers ( int  pagesPerBuffer,
int  levelStep,
int  maxLevel 
)

Definition at line 48 of file gistbuildbuffers.c.

References GISTBuildBuffers::bufferEmptyingQueue, GISTBuildBuffers::buffersOnLevels, GISTBuildBuffers::buffersOnLevelsLen, BufFileCreateTemp(), GISTBuildBuffers::context, CurrentMemoryContext, HASHCTL::entrysize, GISTBuildBuffers::freeBlocks, GISTBuildBuffers::freeBlocksLen, HASH_BLOBS, HASH_CONTEXT, hash_create(), HASH_ELEM, HASHCTL::hcxt, HASHCTL::keysize, GISTBuildBuffers::levelStep, GISTBuildBuffers::loadedBuffers, GISTBuildBuffers::loadedBuffersCount, GISTBuildBuffers::loadedBuffersLen, GISTBuildBuffers::nFileBlocks, GISTBuildBuffers::nFreeBlocks, NIL, GISTBuildBuffers::nodeBuffersTab, GISTBuildBuffers::pagesPerBuffer, palloc(), GISTBuildBuffers::pfile, and GISTBuildBuffers::rootlevel.

Referenced by gistInitBuffering().

49 {
50  GISTBuildBuffers *gfbb;
51  HASHCTL hashCtl;
52 
53  gfbb = palloc(sizeof(GISTBuildBuffers));
54  gfbb->pagesPerBuffer = pagesPerBuffer;
55  gfbb->levelStep = levelStep;
56 
57  /*
58  * Create a temporary file to hold buffer pages that are swapped out of
59  * memory.
60  */
61  gfbb->pfile = BufFileCreateTemp(false);
62  gfbb->nFileBlocks = 0;
63 
64  /* Initialize free page management. */
65  gfbb->nFreeBlocks = 0;
66  gfbb->freeBlocksLen = 32;
67  gfbb->freeBlocks = (long *) palloc(gfbb->freeBlocksLen * sizeof(long));
68 
69  /*
70  * Current memory context will be used for all in-memory data structures
71  * of buffers which are persistent during buffering build.
72  */
74 
75  /*
76  * nodeBuffersTab hash is association between index blocks and it's
77  * buffers.
78  */
79  memset(&hashCtl, 0, sizeof(hashCtl));
80  hashCtl.keysize = sizeof(BlockNumber);
81  hashCtl.entrysize = sizeof(GISTNodeBuffer);
82  hashCtl.hcxt = CurrentMemoryContext;
83  gfbb->nodeBuffersTab = hash_create("gistbuildbuffers",
84  1024,
85  &hashCtl,
87 
88  gfbb->bufferEmptyingQueue = NIL;
89 
90  /*
91  * Per-level node buffers lists for final buffers emptying process. Node
92  * buffers are inserted here when they are created.
93  */
94  gfbb->buffersOnLevelsLen = 1;
95  gfbb->buffersOnLevels = (List **) palloc(sizeof(List *) *
96  gfbb->buffersOnLevelsLen);
97  gfbb->buffersOnLevels[0] = NIL;
98 
99  /*
100  * Block numbers of node buffers which last pages are currently loaded
101  * into main memory.
102  */
103  gfbb->loadedBuffersLen = 32;
105  sizeof(GISTNodeBuffer *));
106  gfbb->loadedBuffersCount = 0;
107 
108  gfbb->rootlevel = maxLevel;
109 
110  return gfbb;
111 }
#define NIL
Definition: pg_list.h:69
#define HASH_CONTEXT
Definition: hsearch.h:93
#define HASH_ELEM
Definition: hsearch.h:87
MemoryContext hcxt
Definition: hsearch.h:78
MemoryContext context
Definition: gist_private.h:328
List ** buffersOnLevels
Definition: gist_private.h:355
Size entrysize
Definition: hsearch.h:73
uint32 BlockNumber
Definition: block.h:31
BufFile * BufFileCreateTemp(bool interXact)
Definition: buffile.c:166
List * bufferEmptyingQueue
Definition: gist_private.h:344
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
#define HASH_BLOBS
Definition: hsearch.h:88
HTAB * hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)
Definition: dynahash.c:301
Size keysize
Definition: hsearch.h:72
GISTNodeBuffer ** loadedBuffers
Definition: gist_private.h:362
void * palloc(Size size)
Definition: mcxt.c:891
Definition: pg_list.h:45
bool gistinsert ( Relation  r,
Datum values,
bool isnull,
ItemPointer  ht_ctid,
Relation  heapRel,
IndexUniqueCheck  checkUnique,
struct IndexInfo indexInfo 
)

Definition at line 147 of file gist.c.

References createTempGistContext(), gistdoinsert(), gistFormTuple(), IndexInfo::ii_AmCache, IndexInfo::ii_Context, initGISTstate(), MemoryContextReset(), MemoryContextSwitchTo(), NULL, and GISTSTATE::tempCxt.

Referenced by gisthandler().

151 {
152  GISTSTATE *giststate = (GISTSTATE *) indexInfo->ii_AmCache;
153  IndexTuple itup;
154  MemoryContext oldCxt;
155 
156  /* Initialize GISTSTATE cache if first call in this statement */
157  if (giststate == NULL)
158  {
159  oldCxt = MemoryContextSwitchTo(indexInfo->ii_Context);
160  giststate = initGISTstate(r);
161  giststate->tempCxt = createTempGistContext();
162  indexInfo->ii_AmCache = (void *) giststate;
163  MemoryContextSwitchTo(oldCxt);
164  }
165 
166  oldCxt = MemoryContextSwitchTo(giststate->tempCxt);
167 
168  itup = gistFormTuple(giststate, r,
169  values, isnull, true /* size is currently bogus */ );
170  itup->t_tid = *ht_ctid;
171 
172  gistdoinsert(r, itup, 0, giststate);
173 
174  /* cleanup */
175  MemoryContextSwitchTo(oldCxt);
176  MemoryContextReset(giststate->tempCxt);
177 
178  return false;
179 }
MemoryContext ii_Context
Definition: execnodes.h:82
MemoryContext createTempGistContext(void)
Definition: gist.c:110
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:135
void gistdoinsert(Relation r, IndexTuple itup, Size freespace, GISTSTATE *giststate)
Definition: gist.c:601
MemoryContext tempCxt
Definition: gist_private.h:79
void * ii_AmCache
Definition: execnodes.h:81
GISTSTATE * initGISTstate(Relation index)
Definition: gist.c:1423
#define NULL
Definition: c.h:226
static Datum values[MAXATTR]
Definition: bootstrap.c:162
IndexTuple gistFormTuple(GISTSTATE *giststate, Relation r, Datum attdata[], bool isnull[], bool isleaf)
Definition: gistutil.c:566
IndexTuple* gistjoinvector ( IndexTuple itvec,
int *  len,
IndexTuple additvec,
int  addlen 
)

Definition at line 112 of file gistutil.c.

References memmove, and repalloc().

Referenced by gistplacetopage().

113 {
114  itvec = (IndexTuple *) repalloc((void *) itvec, sizeof(IndexTuple) * ((*len) + addlen));
115  memmove(&itvec[*len], additvec, sizeof(IndexTuple) * addlen);
116  *len += addlen;
117  return itvec;
118 }
#define memmove(d, s, c)
Definition: c.h:1058
IndexTupleData * IndexTuple
Definition: itup.h:53
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1021
bool gistKeyIsEQ ( GISTSTATE giststate,
int  attno,
Datum  a,
Datum  b 
)

Definition at line 278 of file gistutil.c.

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

Referenced by gistgetadjusted(), and gistUserPicksplit().

279 {
280  bool result;
281 
282  FunctionCall3Coll(&giststate->equalFn[attno],
283  giststate->supportCollation[attno],
284  a, b,
285  PointerGetDatum(&result));
286  return result;
287 }
Oid supportCollation[INDEX_MAX_KEYS]
Definition: gist_private.h:96
#define PointerGetDatum(X)
Definition: postgres.h:564
FmgrInfo equalFn[INDEX_MAX_KEYS]
Definition: gist_private.h:91
Datum FunctionCall3Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2, Datum arg3)
Definition: fmgr.c:1328
void gistMakeUnionItVec ( GISTSTATE giststate,
IndexTuple itvec,
int  len,
Datum attr,
bool isnull 
)

Definition at line 153 of file gistutil.c.

References FALSE, FunctionCall2Coll(), GEVHDRSZ, gistdentryinit(), i, index_getattr, GistEntryVector::n, tupleDesc::natts, NULL, palloc(), PointerGetDatum, GISTSTATE::supportCollation, TRUE, GISTSTATE::tupdesc, GISTSTATE::unionFn, and GistEntryVector::vector.

Referenced by gistunion(), and gistunionsubkeyvec().

155 {
156  int i;
157  GistEntryVector *evec;
158  int attrsize;
159 
160  evec = (GistEntryVector *) palloc((len + 2) * sizeof(GISTENTRY) + GEVHDRSZ);
161 
162  for (i = 0; i < giststate->tupdesc->natts; i++)
163  {
164  int j;
165 
166  /* Collect non-null datums for this column */
167  evec->n = 0;
168  for (j = 0; j < len; j++)
169  {
170  Datum datum;
171  bool IsNull;
172 
173  datum = index_getattr(itvec[j], i + 1, giststate->tupdesc, &IsNull);
174  if (IsNull)
175  continue;
176 
177  gistdentryinit(giststate, i,
178  evec->vector + evec->n,
179  datum,
180  NULL, NULL, (OffsetNumber) 0,
181  FALSE, IsNull);
182  evec->n++;
183  }
184 
185  /* If this column was all NULLs, the union is NULL */
186  if (evec->n == 0)
187  {
188  attr[i] = (Datum) 0;
189  isnull[i] = TRUE;
190  }
191  else
192  {
193  if (evec->n == 1)
194  {
195  /* unionFn may expect at least two inputs */
196  evec->n = 2;
197  evec->vector[1] = evec->vector[0];
198  }
199 
200  /* Make union and store in attr array */
201  attr[i] = FunctionCall2Coll(&giststate->unionFn[i],
202  giststate->supportCollation[i],
203  PointerGetDatum(evec),
204  PointerGetDatum(&attrsize));
205 
206  isnull[i] = FALSE;
207  }
208  }
209 }
TupleDesc tupdesc
Definition: gist_private.h:81
Oid supportCollation[INDEX_MAX_KEYS]
Definition: gist_private.h:96
#define PointerGetDatum(X)
Definition: postgres.h:564
int32 n
Definition: gist.h:160
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1306
int natts
Definition: tupdesc.h:73
uint16 OffsetNumber
Definition: off.h:24
GISTENTRY vector[FLEXIBLE_ARRAY_MEMBER]
Definition: gist.h:161
#define GEVHDRSZ
Definition: gist.h:164
void gistdentryinit(GISTSTATE *giststate, int nkey, GISTENTRY *e, Datum k, Relation r, Page pg, OffsetNumber o, bool l, bool isNull)
Definition: gistutil.c:543
struct GISTENTRY GISTENTRY
#define FALSE
Definition: c.h:218
uintptr_t Datum
Definition: postgres.h:374
#define NULL
Definition: c.h:226
#define index_getattr(tup, attnum, tupleDesc, isnull)
Definition: itup.h:100
void * palloc(Size size)
Definition: mcxt.c:891
int i
#define TRUE
Definition: c.h:214
FmgrInfo unionFn[INDEX_MAX_KEYS]
Definition: gist_private.h:86
void gistMakeUnionKey ( GISTSTATE giststate,
int  attno,
GISTENTRY entry1,
bool  isnull1,
GISTENTRY entry2,
bool  isnull2,
Datum dst,
bool dstisnull 
)

Definition at line 230 of file gistutil.c.

References FALSE, FunctionCall2Coll(), GEVHDRSZ, GistEntryVector::n, PointerGetDatum, GISTSTATE::supportCollation, TRUE, GISTSTATE::unionFn, and GistEntryVector::vector.

Referenced by gistgetadjusted(), and supportSecondarySplit().

234 {
235  /* we need a GistEntryVector with room for exactly 2 elements */
236  union
237  {
238  GistEntryVector gev;
239  char padding[2 * sizeof(GISTENTRY) + GEVHDRSZ];
240  } storage;
241  GistEntryVector *evec = &storage.gev;
242  int dstsize;
243 
244  evec->n = 2;
245 
246  if (isnull1 && isnull2)
247  {
248  *dstisnull = TRUE;
249  *dst = (Datum) 0;
250  }
251  else
252  {
253  if (isnull1 == FALSE && isnull2 == FALSE)
254  {
255  evec->vector[0] = *entry1;
256  evec->vector[1] = *entry2;
257  }
258  else if (isnull1 == FALSE)
259  {
260  evec->vector[0] = *entry1;
261  evec->vector[1] = *entry1;
262  }
263  else
264  {
265  evec->vector[0] = *entry2;
266  evec->vector[1] = *entry2;
267  }
268 
269  *dstisnull = FALSE;
270  *dst = FunctionCall2Coll(&giststate->unionFn[attno],
271  giststate->supportCollation[attno],
272  PointerGetDatum(evec),
273  PointerGetDatum(&dstsize));
274  }
275 }
Oid supportCollation[INDEX_MAX_KEYS]
Definition: gist_private.h:96
#define PointerGetDatum(X)
Definition: postgres.h:564
int32 n
Definition: gist.h:160
Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
Definition: fmgr.c:1306
GISTENTRY vector[FLEXIBLE_ARRAY_MEMBER]
Definition: gist.h:161
#define GEVHDRSZ
Definition: gist.h:164
struct GISTENTRY GISTENTRY
#define FALSE
Definition: c.h:218
uintptr_t Datum
Definition: postgres.h:374
#define TRUE
Definition: c.h:214
FmgrInfo unionFn[INDEX_MAX_KEYS]
Definition: gist_private.h:86
Buffer gistNewBuffer ( Relation  r)

Definition at line 761 of file gistutil.c.

References DataPageDeleteStack::blkno, BufferGetPage, ConditionalLockBuffer(), ExclusiveLock, GetFreeIndexPage(), GIST_EXCLUSIVE, GIST_UNLOCK, gistcheckpage(), GistPageIsDeleted, InvalidBlockNumber, LockBuffer(), LockRelationForExtension(), P_NEW, PageIsNew, ReadBuffer(), RELATION_IS_LOCAL, ReleaseBuffer(), and UnlockRelationForExtension().

Referenced by gistbuild(), and gistplacetopage().

762 {
763  Buffer buffer;
764  bool needLock;
765 
766  /* First, try to get a page from FSM */
767  for (;;)
768  {
769  BlockNumber blkno = GetFreeIndexPage(r);
770 
771  if (blkno == InvalidBlockNumber)
772  break; /* nothing left in FSM */
773 
774  buffer = ReadBuffer(r, blkno);
775 
776  /*
777  * We have to guard against the possibility that someone else already
778  * recycled this page; the buffer may be locked if so.
779  */
780  if (ConditionalLockBuffer(buffer))
781  {
782  Page page = BufferGetPage(buffer);
783 
784  if (PageIsNew(page))
785  return buffer; /* OK to use, if never initialized */
786 
787  gistcheckpage(r, buffer);
788 
789  if (GistPageIsDeleted(page))
790  return buffer; /* OK to use */
791 
792  LockBuffer(buffer, GIST_UNLOCK);
793  }
794 
795  /* Can't use it, so release buffer and try again */
796  ReleaseBuffer(buffer);
797  }
798 
799  /* Must extend the file */
800  needLock = !RELATION_IS_LOCAL(r);
801 
802  if (needLock)
804 
805  buffer = ReadBuffer(r, P_NEW);
806  LockBuffer(buffer, GIST_EXCLUSIVE);
807 
808  if (needLock)
810 
811  return buffer;
812 }
#define GistPageIsDeleted(page)
Definition: gist.h:135
#define ExclusiveLock
Definition: lockdefs.h:44
#define RELATION_IS_LOCAL(relation)
Definition: rel.h:520
#define GIST_UNLOCK
Definition: gist_private.h:45
uint32 BlockNumber
Definition: block.h:31
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3292
#define P_NEW
Definition: bufmgr.h:82
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
bool ConditionalLockBuffer(Buffer buffer)
Definition: bufmgr.c:3555
void LockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition: lmgr.c:332
void UnlockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition: lmgr.c:382
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3529
BlockNumber GetFreeIndexPage(Relation rel)
Definition: indexfsm.c:38
void gistcheckpage(Relation rel, Buffer buf)
Definition: gistutil.c:722
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:594
#define InvalidBlockNumber
Definition: block.h:33
#define PageIsNew(page)
Definition: bufpage.h:226
#define GIST_EXCLUSIVE
Definition: gist_private.h:44
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:74
bool gistnospace ( Page  page,
IndexTuple itvec,
int  len,
OffsetNumber  todelete,
Size  freespace 
)

Definition at line 57 of file gistutil.c.

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

Referenced by gistplacetopage().

58 {
59  unsigned int size = freespace,
60  deleted = 0;
61  int i;
62 
63  for (i = 0; i < len; i++)
64  size += IndexTupleSize(itvec[i]) + sizeof(ItemIdData);
65 
66  if (todelete != InvalidOffsetNumber)
67  {
68  IndexTuple itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, todelete));
69 
70  deleted = IndexTupleSize(itup) + sizeof(ItemIdData);
71  }
72 
73  return (PageGetFreeSpace(page) + deleted < size);
74 }
Size PageGetFreeSpace(Page page)
Definition: bufpage.c:582
IndexTupleData * IndexTuple
Definition: itup.h:53
struct ItemIdData ItemIdData
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:232
#define InvalidOffsetNumber
Definition: off.h:26
int i
#define PageGetItem(page, itemId)
Definition: bufpage.h:337
#define IndexTupleSize(itup)
Definition: itup.h:70
bytea* gistoptions ( Datum  reloptions,
bool  validate 
)

Definition at line 815 of file gistutil.c.

References allocateReloptStruct(), fillfactor, fillRelOptions(), lengthof, NULL, offsetof, options, parseRelOptions(), pfree(), RELOPT_KIND_GIST, RELOPT_TYPE_INT, and RELOPT_TYPE_STRING.

Referenced by gisthandler().

816 {
818  GiSTOptions *rdopts;
819  int numoptions;
820  static const relopt_parse_elt tab[] = {
821  {"fillfactor", RELOPT_TYPE_INT, offsetof(GiSTOptions, fillfactor)},
822  {"buffering", RELOPT_TYPE_STRING, offsetof(GiSTOptions, bufferingModeOffset)}
823  };
824 
825  options = parseRelOptions(reloptions, validate, RELOPT_KIND_GIST,
826  &numoptions);
827 
828  /* if none set, we're done */
829  if (numoptions == 0)
830  return NULL;
831 
832  rdopts = allocateReloptStruct(sizeof(GiSTOptions), options, numoptions);
833 
834  fillRelOptions((void *) rdopts, sizeof(GiSTOptions), options, numoptions,
835  validate, tab, lengthof(tab));
836 
837  pfree(options);
838 
839  return (bytea *) rdopts;
840 }
#define lengthof(array)
Definition: c.h:558
void pfree(void *pointer)
Definition: mcxt.c:992
int fillfactor
Definition: pgbench.c:112
void * allocateReloptStruct(Size base, relopt_value *options, int numoptions)
Definition: reloptions.c:1174
static char ** options
void fillRelOptions(void *rdopts, Size basesize, relopt_value *options, int numoptions, bool validate, const relopt_parse_elt *elems, int numelems)
Definition: reloptions.c:1198
#define NULL
Definition: c.h:226
Definition: c.h:435
relopt_value * parseRelOptions(Datum options, bool validate, relopt_kind kind, int *numrelopts)
Definition: reloptions.c:975
#define offsetof(type, field)
Definition: c.h:551
float gistpenalty ( GISTSTATE giststate,
int  attno,
GISTENTRY key1,
bool  isNull1,
GISTENTRY key2,
bool  isNull2 
)

Definition at line 667 of file gistutil.c.

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

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

670 {
671  float penalty = 0.0;
672 
673  if (giststate->penaltyFn[attno].fn_strict == FALSE ||
674  (isNullOrig == FALSE && isNullAdd == FALSE))
675  {
676  FunctionCall3Coll(&giststate->penaltyFn[attno],
677  giststate->supportCollation[attno],
678  PointerGetDatum(orig),
679  PointerGetDatum(add),
680  PointerGetDatum(&penalty));
681  /* disallow negative or NaN penalty */
682  if (isnan(penalty) || penalty < 0.0)
683  penalty = 0.0;
684  }
685  else if (isNullOrig && isNullAdd)
686  penalty = 0.0;
687  else
688  {
689  /* try to prevent mixing null and non-null values */
690  penalty = get_float4_infinity();
691  }
692 
693  return penalty;
694 }
Oid supportCollation[INDEX_MAX_KEYS]
Definition: gist_private.h:96
#define PointerGetDatum(X)
Definition: postgres.h:564
float get_float4_infinity(void)
Definition: float.c:146
bool fn_strict
Definition: fmgr.h:58
#define FALSE
Definition: c.h:218
FmgrInfo penaltyFn[INDEX_MAX_KEYS]
Definition: gist_private.h:89
Datum FunctionCall3Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2, Datum arg3)
Definition: fmgr.c:1328
bool gistplacetopage ( Relation  rel,
Size  freespace,
GISTSTATE giststate,
Buffer  buffer,
IndexTuple itup,
int  ntup,
OffsetNumber  oldoffnum,
BlockNumber newblkno,
Buffer  leftchildbuf,
List **  splitinfo,
bool  markleftchild 
)

Definition at line 212 of file gist.c.

References gistxlogPage::blkno, DataPageDeleteStack::blkno, SplitedPageLayout::block, GISTPageSplitInfo::buf, SplitedPageLayout::buffer, BufferGetBlockNumber(), BufferGetPage, BufferIsValid, GISTPageSplitInfo::downlink, elog, END_CRIT_SECTION, ERROR, F_LEAF, FirstOffsetNumber, GIST_MAX_SPLIT_PAGES, GIST_ROOT_BLKNO, GistClearFollowRight, gistextractpage(), gistfillbuffer(), gistfillitupvec(), GistFollowRight, gistGetFakeLSN(), GISTInitBuffer(), gistjoinvector(), GistMarkFollowRight, gistNewBuffer(), gistnospace(), GistPageGetNSN, GistPageGetOpaque, GistPageHasGarbage, GistPageIsLeaf, GistPageSetNSN, gistSplit(), GistTupleSetValid, gistvacuumpage(), gistXLogSplit(), gistXLogUpdate(), i, IndexTupleSize, InvalidBlockNumber, InvalidOffsetNumber, ItemPointerEquals(), ItemPointerSetBlockNumber, SplitedPageLayout::itup, lappend(), SplitedPageLayout::lenlist, SplitedPageLayout::list, MarkBufferDirty(), memmove, SplitedPageLayout::next, NIL, NULL, gistxlogPage::num, OffsetNumberIsValid, SplitedPageLayout::page, PageAddItem, PageGetTempPageCopySpecial(), PageIndexTupleDelete(), PageIndexTupleOverwrite(), PageRestoreTempPage(), PageSetLSN, palloc(), RelationGetRelationName, RelationNeedsWAL, START_CRIT_SECTION, IndexTupleData::t_tid, UnlockReleaseBuffer(), and XLogEnsureRecordSpace().

Referenced by gistbufferinginserttuples(), and gistinserttuples().

219 {
220  BlockNumber blkno = BufferGetBlockNumber(buffer);
221  Page page = BufferGetPage(buffer);
222  bool is_leaf = (GistPageIsLeaf(page)) ? true : false;
223  XLogRecPtr recptr;
224  int i;
225  bool is_split;
226 
227  /*
228  * Refuse to modify a page that's incompletely split. This should not
229  * happen because we finish any incomplete splits while we walk down the
230  * tree. However, it's remotely possible that another concurrent inserter
231  * splits a parent page, and errors out before completing the split. We
232  * will just throw an error in that case, and leave any split we had in
233  * progress unfinished too. The next insert that comes along will clean up
234  * the mess.
235  */
236  if (GistFollowRight(page))
237  elog(ERROR, "concurrent GiST page split was incomplete");
238 
239  *splitinfo = NIL;
240 
241  /*
242  * if isupdate, remove old key: This node's key has been modified, either
243  * because a child split occurred or because we needed to adjust our key
244  * for an insert in a child node. Therefore, remove the old version of
245  * this node's key.
246  *
247  * for WAL replay, in the non-split case we handle this by setting up a
248  * one-element todelete array; in the split case, it's handled implicitly
249  * because the tuple vector passed to gistSplit won't include this tuple.
250  */
251  is_split = gistnospace(page, itup, ntup, oldoffnum, freespace);
252 
253  /*
254  * If leaf page is full, try at first to delete dead tuples. And then
255  * check again.
256  */
257  if (is_split && GistPageIsLeaf(page) && GistPageHasGarbage(page))
258  {
259  gistvacuumpage(rel, page, buffer);
260  is_split = gistnospace(page, itup, ntup, oldoffnum, freespace);
261  }
262 
263  if (is_split)
264  {
265  /* no space for insertion */
266  IndexTuple *itvec;
267  int tlen;
268  SplitedPageLayout *dist = NULL,
269  *ptr;
270  BlockNumber oldrlink = InvalidBlockNumber;
271  GistNSN oldnsn = 0;
272  SplitedPageLayout rootpg;
273  bool is_rootsplit;
274  int npage;
275 
276  is_rootsplit = (blkno == GIST_ROOT_BLKNO);
277 
278  /*
279  * Form index tuples vector to split. If we're replacing an old tuple,
280  * remove the old version from the vector.
281  */
282  itvec = gistextractpage(page, &tlen);
283  if (OffsetNumberIsValid(oldoffnum))
284  {
285  /* on inner page we should remove old tuple */
286  int pos = oldoffnum - FirstOffsetNumber;
287 
288  tlen--;
289  if (pos != tlen)
290  memmove(itvec + pos, itvec + pos + 1, sizeof(IndexTuple) * (tlen - pos));
291  }
292  itvec = gistjoinvector(itvec, &tlen, itup, ntup);
293  dist = gistSplit(rel, page, itvec, tlen, giststate);
294 
295  /*
296  * Check that split didn't produce too many pages.
297  */
298  npage = 0;
299  for (ptr = dist; ptr; ptr = ptr->next)
300  npage++;
301  /* in a root split, we'll add one more page to the list below */
302  if (is_rootsplit)
303  npage++;
304  if (npage > GIST_MAX_SPLIT_PAGES)
305  elog(ERROR, "GiST page split into too many halves (%d, maximum %d)",
306  npage, GIST_MAX_SPLIT_PAGES);
307 
308  /*
309  * Set up pages to work with. Allocate new buffers for all but the
310  * leftmost page. The original page becomes the new leftmost page, and
311  * is just replaced with the new contents.
312  *
313  * For a root-split, allocate new buffers for all child pages, the
314  * original page is overwritten with new root page containing
315  * downlinks to the new child pages.
316  */
317  ptr = dist;
318  if (!is_rootsplit)
319  {
320  /* save old rightlink and NSN */
321  oldrlink = GistPageGetOpaque(page)->rightlink;
322  oldnsn = GistPageGetNSN(page);
323 
324  dist->buffer = buffer;
325  dist->block.blkno = BufferGetBlockNumber(buffer);
327 
328  /* clean all flags except F_LEAF */
329  GistPageGetOpaque(dist->page)->flags = (is_leaf) ? F_LEAF : 0;
330 
331  ptr = ptr->next;
332  }
333  for (; ptr; ptr = ptr->next)
334  {
335  /* Allocate new page */
336  ptr->buffer = gistNewBuffer(rel);
337  GISTInitBuffer(ptr->buffer, (is_leaf) ? F_LEAF : 0);
338  ptr->page = BufferGetPage(ptr->buffer);
339  ptr->block.blkno = BufferGetBlockNumber(ptr->buffer);
340  }
341 
342  /*
343  * Now that we know which blocks the new pages go to, set up downlink
344  * tuples to point to them.
345  */
346  for (ptr = dist; ptr; ptr = ptr->next)
347  {
348  ItemPointerSetBlockNumber(&(ptr->itup->t_tid), ptr->block.blkno);
349  GistTupleSetValid(ptr->itup);
350  }
351 
352  /*
353  * If this is a root split, we construct the new root page with the
354  * downlinks here directly, instead of requiring the caller to insert
355  * them. Add the new root page to the list along with the child pages.
356  */
357  if (is_rootsplit)
358  {
359  IndexTuple *downlinks;
360  int ndownlinks = 0;
361  int i;
362 
363  rootpg.buffer = buffer;
365  GistPageGetOpaque(rootpg.page)->flags = 0;
366 
367  /* Prepare a vector of all the downlinks */
368  for (ptr = dist; ptr; ptr = ptr->next)
369  ndownlinks++;
370  downlinks = palloc(sizeof(IndexTuple) * ndownlinks);
371  for (i = 0, ptr = dist; ptr; ptr = ptr->next)
372  downlinks[i++] = ptr->itup;
373 
374  rootpg.block.blkno = GIST_ROOT_BLKNO;
375  rootpg.block.num = ndownlinks;
376  rootpg.list = gistfillitupvec(downlinks, ndownlinks,
377  &(rootpg.lenlist));
378  rootpg.itup = NULL;
379 
380  rootpg.next = dist;
381  dist = &rootpg;
382  }
383  else
384  {
385  /* Prepare split-info to be returned to caller */
386  for (ptr = dist; ptr; ptr = ptr->next)
387  {
389 
390  si->buf = ptr->buffer;
391  si->downlink = ptr->itup;
392  *splitinfo = lappend(*splitinfo, si);
393  }
394  }
395 
396  /*
397  * Fill all pages. All the pages are new, ie. freshly allocated empty
398  * pages, or a temporary copy of the old page.
399  */
400  for (ptr = dist; ptr; ptr = ptr->next)
401  {
402  char *data = (char *) (ptr->list);
403 
404  for (i = 0; i < ptr->block.num; i++)
405  {
406  IndexTuple thistup = (IndexTuple) data;
407 
408  if (PageAddItem(ptr->page, (Item) data, IndexTupleSize(thistup), i + FirstOffsetNumber, false, false) == InvalidOffsetNumber)
409  elog(ERROR, "failed to add item to index page in \"%s\"", RelationGetRelationName(rel));
410 
411  /*
412  * If this is the first inserted/updated tuple, let the caller
413  * know which page it landed on.
414  */
415  if (newblkno && ItemPointerEquals(&thistup->t_tid, &(*itup)->t_tid))
416  *newblkno = ptr->block.blkno;
417 
418  data += IndexTupleSize(thistup);
419  }
420 
421  /* Set up rightlinks */
422  if (ptr->next && ptr->block.blkno != GIST_ROOT_BLKNO)
423  GistPageGetOpaque(ptr->page)->rightlink =
424  ptr->next->block.blkno;
425  else
426  GistPageGetOpaque(ptr->page)->rightlink = oldrlink;
427 
428  /*
429  * Mark the all but the right-most page with the follow-right
430  * flag. It will be cleared as soon as the downlink is inserted
431  * into the parent, but this ensures that if we error out before
432  * that, the index is still consistent. (in buffering build mode,
433  * any error will abort the index build anyway, so this is not
434  * needed.)
435  */
436  if (ptr->next && !is_rootsplit && markfollowright)
437  GistMarkFollowRight(ptr->page);
438  else
439  GistClearFollowRight(ptr->page);
440 
441  /*
442  * Copy the NSN of the original page to all pages. The
443  * F_FOLLOW_RIGHT flags ensure that scans will follow the
444  * rightlinks until the downlinks are inserted.
445  */
446  GistPageSetNSN(ptr->page, oldnsn);
447  }
448 
449  /*
450  * gistXLogSplit() needs to WAL log a lot of pages, prepare WAL
451  * insertion for that. NB: The number of pages and data segments
452  * specified here must match the calculations in gistXLogSplit()!
453  */
454  if (RelationNeedsWAL(rel))
455  XLogEnsureRecordSpace(npage, 1 + npage * 2);
456 
458 
459  /*
460  * Must mark buffers dirty before XLogInsert, even though we'll still
461  * be changing their opaque fields below.
462  */
463  for (ptr = dist; ptr; ptr = ptr->next)
464  MarkBufferDirty(ptr->buffer);
465  if (BufferIsValid(leftchildbuf))
466  MarkBufferDirty(leftchildbuf);
467 
468  /*
469  * The first page in the chain was a temporary working copy meant to
470  * replace the old page. Copy it over the old page.
471  */
473  dist->page = BufferGetPage(dist->buffer);
474 
475  /* Write the WAL record */
476  if (RelationNeedsWAL(rel))
477  recptr = gistXLogSplit(is_leaf,
478  dist, oldrlink, oldnsn, leftchildbuf,
479  markfollowright);
480  else
481  recptr = gistGetFakeLSN(rel);
482 
483  for (ptr = dist; ptr; ptr = ptr->next)
484  {
485  PageSetLSN(ptr->page, recptr);
486  }
487 
488  /*
489  * Return the new child buffers to the caller.
490  *
491  * If this was a root split, we've already inserted the downlink
492  * pointers, in the form of a new root page. Therefore we can release
493  * all the new buffers, and keep just the root page locked.
494  */
495  if (is_rootsplit)
496  {
497  for (ptr = dist->next; ptr; ptr = ptr->next)
498  UnlockReleaseBuffer(ptr->buffer);
499  }
500  }
501  else
502  {
503  /*
504  * Enough space. We always get here if ntup==0.
505  */
507 
508  /*
509  * Delete old tuple if any, then insert new tuple(s) if any. If
510  * possible, use the fast path of PageIndexTupleOverwrite.
511  */
512  if (OffsetNumberIsValid(oldoffnum))
513  {
514  if (ntup == 1)
515  {
516  /* One-for-one replacement, so use PageIndexTupleOverwrite */
517  if (!PageIndexTupleOverwrite(page, oldoffnum, (Item) *itup,
518  IndexTupleSize(*itup)))
519  elog(ERROR, "failed to add item to index page in \"%s\"",
521  }
522  else
523  {
524  /* Delete old, then append new tuple(s) to page */
525  PageIndexTupleDelete(page, oldoffnum);
526  gistfillbuffer(page, itup, ntup, InvalidOffsetNumber);
527  }
528  }
529  else
530  {
531  /* Just append new tuples at the end of the page */
532  gistfillbuffer(page, itup, ntup, InvalidOffsetNumber);
533  }
534 
535  MarkBufferDirty(buffer);
536 
537  if (BufferIsValid(leftchildbuf))
538  MarkBufferDirty(leftchildbuf);
539 
540  if (RelationNeedsWAL(rel))
541  {
542  OffsetNumber ndeloffs = 0,
543  deloffs[1];
544 
545  if (OffsetNumberIsValid(oldoffnum))
546  {
547  deloffs[0] = oldoffnum;
548  ndeloffs = 1;
549  }
550 
551  recptr = gistXLogUpdate(buffer,
552  deloffs, ndeloffs, itup, ntup,
553  leftchildbuf);
554 
555  PageSetLSN(page, recptr);
556  }
557  else
558  {
559  recptr = gistGetFakeLSN(rel);
560  PageSetLSN(page, recptr);
561  }
562 
563  if (newblkno)
564  *newblkno = blkno;
565  }
566 
567  /*
568  * If we inserted the downlink for a child page, set NSN and clear
569  * F_FOLLOW_RIGHT flag on the left child, so that concurrent scans know to
570  * follow the rightlink if and only if they looked at the parent page
571  * before we inserted the downlink.
572  *
573  * Note that we do this *after* writing the WAL record. That means that
574  * the possible full page image in the WAL record does not include these
575  * changes, and they must be replayed even if the page is restored from
576  * the full page image. There's a chicken-and-egg problem: if we updated
577  * the child pages first, we wouldn't know the recptr of the WAL record
578  * we're about to write.
579  */
580  if (BufferIsValid(leftchildbuf))
581  {
582  Page leftpg = BufferGetPage(leftchildbuf);
583 
584  GistPageSetNSN(leftpg, recptr);
585  GistClearFollowRight(leftpg);
586 
587  PageSetLSN(leftpg, recptr);
588  }
589 
591 
592  return is_split;
593 }
#define GistFollowRight(page)
Definition: gist.h:147
#define NIL
Definition: pg_list.h:69
#define GistPageGetNSN(page)
Definition: gist.h:151
void PageRestoreTempPage(Page tempPage, Page oldPage)
Definition: bufpage.c:407
BlockNumber blkno
Definition: gist_private.h:182
void PageIndexTupleDelete(Page page, OffsetNumber offnum)
Definition: bufpage.c:700
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1445
ItemPointerData t_tid
Definition: itup.h:37
void gistfillbuffer(Page page, IndexTuple *itup, int len, OffsetNumber off)
Definition: gistutil.c:32
#define END_CRIT_SECTION()
Definition: miscadmin.h:132
Pointer Item
Definition: item.h:17
#define GistPageSetNSN(page, val)
Definition: gist.h:152
#define START_CRIT_SECTION()
Definition: miscadmin.h:130
#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap)
Definition: bufpage.h:413
#define GistPageHasGarbage(page)
Definition: gist.h:143
uint32 BlockNumber
Definition: block.h:31
IndexTupleData * list
Definition: gist_private.h:190
XLogRecPtr gistGetFakeLSN(Relation rel)
Definition: gistutil.c:945
uint16 OffsetNumber
Definition: off.h:24
Page PageGetTempPageCopySpecial(Page page)
Definition: bufpage.c:385
gistxlogPage block
Definition: gist_private.h:189
XLogRecPtr gistXLogSplit(bool page_is_leaf, SplitedPageLayout *dist, BlockNumber origrlink, GistNSN orignsn, Buffer leftchildbuf, bool markfollowright)
Definition: gistxlog.c:393
IndexTuple * gistextractpage(Page page, int *len)
Definition: gistutil.c:93
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3315
#define ERROR
Definition: elog.h:43
#define GIST_MAX_SPLIT_PAGES
Definition: gist_private.h:40
IndexTuple downlink
Definition: gist_private.h:398
bool PageIndexTupleOverwrite(Page page, OffsetNumber offnum, Item newtup, Size newsize)
Definition: bufpage.c:1039
#define memmove(d, s, c)
Definition: c.h:1058
#define FirstOffsetNumber
Definition: off.h:27
IndexTupleData * IndexTuple
Definition: itup.h:53
bool gistnospace(Page page, IndexTuple *itvec, int len, OffsetNumber todelete, Size freespace)
Definition: gistutil.c:57
#define RelationGetRelationName(relation)
Definition: rel.h:433
struct SplitedPageLayout * next
Definition: gist_private.h:196
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
static void gistvacuumpage(Relation rel, Page page, Buffer buffer)
Definition: gist.c:1521
List * lappend(List *list, void *datum)
Definition: list.c:128
#define GistPageIsLeaf(page)
Definition: gist.h:132
#define GistTupleSetValid(itup)
Definition: gist_private.h:276
#define GistClearFollowRight(page)
Definition: gist.h:149
IndexTuple * gistjoinvector(IndexTuple *itvec, int *len, IndexTuple *additvec, int addlen)
Definition: gistutil.c:112
SplitedPageLayout * gistSplit(Relation r, Page page, IndexTuple *itup, int len, GISTSTATE *giststate)
Definition: gist.c:1338
#define InvalidOffsetNumber
Definition: off.h:26
XLogRecPtr gistXLogUpdate(Buffer buffer, OffsetNumber *todelete, int ntodelete, IndexTuple *itup, int ituplen, Buffer leftchildbuf)
Definition: gistxlog.c:457
#define GistPageGetOpaque(page)
Definition: gist.h:130
#define NULL
Definition: c.h:226
uint64 XLogRecPtr
Definition: xlogdefs.h:21
IndexTupleData * gistfillitupvec(IndexTuple *vec, int veclen, int *memlen)
Definition: gistutil.c:125
#define InvalidBlockNumber
Definition: block.h:33
void XLogEnsureRecordSpace(int max_block_id, int ndatas)
Definition: xloginsert.c:146
#define BufferIsValid(bufnum)
Definition: bufmgr.h:114
#define ItemPointerSetBlockNumber(pointer, blockNumber)
Definition: itemptr.h:97
#define GistMarkFollowRight(page)
Definition: gist.h:148
#define RelationNeedsWAL(relation)
Definition: rel.h:502
bool ItemPointerEquals(ItemPointer pointer1, ItemPointer pointer2)
Definition: itemptr.c:29
XLogRecPtr GistNSN
Definition: gist.h:50
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2588
void * palloc(Size size)
Definition: mcxt.c:891
#define F_LEAF
Definition: gist.h:42
int i
#define GIST_ROOT_BLKNO
Definition: gist_private.h:249
#define OffsetNumberIsValid(offsetNumber)
Definition: off.h:40
void GISTInitBuffer(Buffer b, uint32 f)
Definition: gistutil.c:700
#define elog
Definition: elog.h:219
#define PageSetLSN(page, lsn)
Definition: bufpage.h:365
Buffer gistNewBuffer(Relation r)
Definition: gistutil.c:761
Pointer Page
Definition: bufpage.h:74
#define IndexTupleSize(itup)
Definition: itup.h:70
bool gistPopItupFromNodeBuffer ( GISTBuildBuffers gfbb,
GISTNodeBuffer nodeBuffer,
IndexTuple item 
)

Definition at line 410 of file gistbuildbuffers.c.

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

Referenced by gistProcessEmptyingQueue(), and gistRelocateBuildBuffersOnSplit().

412 {
413  /*
414  * If node buffer is empty then return false.
415  */
416  if (nodeBuffer->blocksCount <= 0)
417  return false;
418 
419  /* Load last page of node buffer if needed */
420  if (!nodeBuffer->pageBuffer)
421  gistLoadNodeBuffer(gfbb, nodeBuffer);
422 
423  /*
424  * Get index tuple from last non-empty page.
425  */
426  gistGetItupFromPage(nodeBuffer->pageBuffer, itup);
427 
428  /*
429  * If we just removed the last tuple from the page, fetch previous page on
430  * this node buffer (if any).
431  */
432  if (PAGE_IS_EMPTY(nodeBuffer->pageBuffer))
433  {
434  BlockNumber prevblkno;
435 
436  /*
437  * blocksCount includes the page in pageBuffer, so decrease it now.
438  */
439  nodeBuffer->blocksCount--;
440 
441  /*
442  * If there's more pages, fetch previous one.
443  */
444  prevblkno = nodeBuffer->pageBuffer->prev;
445  if (prevblkno != InvalidBlockNumber)
446  {
447  /* There is a previous page. Fetch it. */
448  Assert(nodeBuffer->blocksCount > 0);
449  ReadTempFileBlock(gfbb->pfile, prevblkno, nodeBuffer->pageBuffer);
450 
451  /*
452  * Now that we've read the block in memory, we can release its
453  * on-disk block for reuse.
454  */
455  gistBuffersReleaseBlock(gfbb, prevblkno);
456  }
457  else
458  {
459  /* No more pages. Free memory. */
460  Assert(nodeBuffer->blocksCount == 0);
461  pfree(nodeBuffer->pageBuffer);
462  nodeBuffer->pageBuffer = NULL;
463  }
464  }
465  return true;
466 }
uint32 BlockNumber
Definition: block.h:31
static void gistBuffersReleaseBlock(GISTBuildBuffers *gfbb, long blocknum)
static void gistLoadNodeBuffer(GISTBuildBuffers *gfbb, GISTNodeBuffer *nodeBuffer)
GISTNodeBufferPage * pageBuffer
Definition: gist_private.h:291
void pfree(void *pointer)
Definition: mcxt.c:992
static void gistGetItupFromPage(GISTNodeBufferPage *pageBuffer, IndexTuple *item)
BlockNumber prev
Definition: gist_private.h:49
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
#define InvalidBlockNumber
Definition: block.h:33
#define PAGE_IS_EMPTY(nbp)
Definition: gist_private.h:58
static void ReadTempFileBlock(BufFile *file, long blknum, void *ptr)
bool gistproperty ( Oid  index_oid,
int  attno,
IndexAMProperty  prop,
const char *  propname,
bool res,
bool isnull 
)

Definition at line 850 of file gistutil.c.

References AMPROCNUM, AMPROP_DISTANCE_ORDERABLE, AMPROP_RETURNABLE, Anum_pg_index_indclass, Assert, CLAOID, DatumGetPointer, GETSTRUCT, GIST_DISTANCE_PROC, GIST_FETCH_PROC, HeapTupleIsValid, INDEXRELID, Int16GetDatum, ObjectIdGetDatum, PG_USED_FOR_ASSERTS_ONLY, ReleaseSysCache(), SearchSysCache1, SearchSysCacheExists4, SysCacheGetAttr(), and oidvector::values.

Referenced by gisthandler().

853 {
854  HeapTuple tuple;
856  Form_pg_opclass rd_opclass;
857  Datum datum;
858  bool disnull;
859  oidvector *indclass;
860  Oid opclass,
861  opfamily,
862  opcintype;
863  int16 procno;
864 
865  /* Only answer column-level inquiries */
866  if (attno == 0)
867  return false;
868 
869  /*
870  * Currently, GiST distance-ordered scans require that there be a distance
871  * function in the opclass with the default types (i.e. the one loaded
872  * into the relcache entry, see initGISTstate). So we assume that if such
873  * a function exists, then there's a reason for it (rather than grubbing
874  * through all the opfamily's operators to find an ordered one).
875  *
876  * Essentially the same code can test whether we support returning the
877  * column data, since that's true if the opclass provides a fetch proc.
878  */
879 
880  switch (prop)
881  {
883  procno = GIST_DISTANCE_PROC;
884  break;
885  case AMPROP_RETURNABLE:
886  procno = GIST_FETCH_PROC;
887  break;
888  default:
889  return false;
890  }
891 
892  /* First we need to know the column's opclass. */
893 
894  tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(index_oid));
895  if (!HeapTupleIsValid(tuple))
896  {
897  *isnull = true;
898  return true;
899  }
900  rd_index = (Form_pg_index) GETSTRUCT(tuple);
901 
902  /* caller is supposed to guarantee this */
903  Assert(attno > 0 && attno <= rd_index->indnatts);
904 
905  datum = SysCacheGetAttr(INDEXRELID, tuple,
906  Anum_pg_index_indclass, &disnull);
907  Assert(!disnull);
908 
909  indclass = ((oidvector *) DatumGetPointer(datum));
910  opclass = indclass->values[attno - 1];
911 
912  ReleaseSysCache(tuple);
913 
914  /* Now look up the opclass family and input datatype. */
915 
916  tuple = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
917  if (!HeapTupleIsValid(tuple))
918  {
919  *isnull = true;
920  return true;
921  }
922  rd_opclass = (Form_pg_opclass) GETSTRUCT(tuple);
923 
924  opfamily = rd_opclass->opcfamily;
925  opcintype = rd_opclass->opcintype;
926 
927  ReleaseSysCache(tuple);
928 
929  /* And now we can check whether the function is provided. */
930 
932  ObjectIdGetDatum(opfamily),
933  ObjectIdGetDatum(opcintype),
934  ObjectIdGetDatum(opcintype),
935  Int16GetDatum(procno));
936  return true;
937 }
signed short int16
Definition: c.h:252
Definition: c.h:474
#define GIST_FETCH_PROC
Definition: gist.h:36
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define Int16GetDatum(X)
Definition: postgres.h:459
#define Anum_pg_index_indclass
Definition: pg_index.h:89
#define SearchSysCacheExists4(cacheId, key1, key2, key3, key4)
Definition: syscache.h:173
unsigned int Oid
Definition: postgres_ext.h:31
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:149
#define ObjectIdGetDatum(X)
Definition: postgres.h:515
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:482
FormData_pg_index * Form_pg_index
Definition: pg_index.h:67
uintptr_t Datum
Definition: postgres.h:374
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1083
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1245
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define Assert(condition)
Definition: c.h:671
#define GIST_DISTANCE_PROC
Definition: gist.h:35
#define DatumGetPointer(X)
Definition: postgres.h:557
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:986
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:68
void gistPushItupToNodeBuffer ( GISTBuildBuffers gfbb,
GISTNodeBuffer nodeBuffer,
IndexTuple  item 
)

Definition at line 340 of file gistbuildbuffers.c.

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

Referenced by gistProcessItup(), and gistRelocateBuildBuffersOnSplit().

342 {
343  /*
344  * Most part of memory operations will be in buffering build persistent
345  * context. So, let's switch to it.
346  */
348 
349  /*
350  * If the buffer is currently empty, create the first page.
351  */
352  if (nodeBuffer->blocksCount == 0)
353  {
354  nodeBuffer->pageBuffer = gistAllocateNewPageBuffer(gfbb);
355  nodeBuffer->blocksCount = 1;
356  gistAddLoadedBuffer(gfbb, nodeBuffer);
357  }
358 
359  /* Load last page of node buffer if it wasn't in memory already */
360  if (!nodeBuffer->pageBuffer)
361  gistLoadNodeBuffer(gfbb, nodeBuffer);
362 
363  /*
364  * Check if there is enough space on the last page for the tuple.
365  */
366  if (PAGE_NO_SPACE(nodeBuffer->pageBuffer, itup))
367  {
368  /*
369  * Nope. Swap previous block to disk and allocate a new one.
370  */
371  BlockNumber blkno;
372 
373  /* Write filled page to the disk */
374  blkno = gistBuffersGetFreeBlock(gfbb);
375  WriteTempFileBlock(gfbb->pfile, blkno, nodeBuffer->pageBuffer);
376 
377  /*
378  * Reset the in-memory page as empty, and link the previous block to
379  * the new page by storing its block number in the prev-link.
380  */
381  PAGE_FREE_SPACE(nodeBuffer->pageBuffer) =
382  BLCKSZ - MAXALIGN(offsetof(GISTNodeBufferPage, tupledata));
383  nodeBuffer->pageBuffer->prev = blkno;
384 
385  /* We've just added one more page */
386  nodeBuffer->blocksCount++;
387  }
388 
389  gistPlaceItupToPage(nodeBuffer->pageBuffer, itup);
390 
391  /*
392  * If the buffer just overflowed, add it to the emptying queue.
393  */
394  if (BUFFER_HALF_FILLED(nodeBuffer, gfbb) && !nodeBuffer->queuedForEmptying)
395  {
396  gfbb->bufferEmptyingQueue = lcons(nodeBuffer,
397  gfbb->bufferEmptyingQueue);
398  nodeBuffer->queuedForEmptying = true;
399  }
400 
401  /* Restore memory context */
402  MemoryContextSwitchTo(oldcxt);
403 }
#define PAGE_FREE_SPACE(nbp)
Definition: gist_private.h:56
static void gistPlaceItupToPage(GISTNodeBufferPage *pageBuffer, IndexTuple item)
static GISTNodeBufferPage * gistAllocateNewPageBuffer(GISTBuildBuffers *gfbb)
MemoryContext context
Definition: gist_private.h:328
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define BUFFER_HALF_FILLED(nodeBuffer, gfbb)
Definition: gist_private.h:311
uint32 BlockNumber
Definition: block.h:31
static void gistLoadNodeBuffer(GISTBuildBuffers *gfbb, GISTNodeBuffer *nodeBuffer)
GISTNodeBufferPage * pageBuffer
Definition: gist_private.h:291
static long gistBuffersGetFreeBlock(GISTBuildBuffers *gfbb)
List * bufferEmptyingQueue
Definition: gist_private.h:344
#define PAGE_NO_SPACE(nbp, itup)
Definition: gist_private.h:60
bool queuedForEmptying
Definition: gist_private.h:294
static void WriteTempFileBlock(BufFile *file, long blknum, void *ptr)
List * lcons(void *datum, List *list)
Definition: list.c:259
BlockNumber prev
Definition: gist_private.h:49
#define MAXALIGN(LEN)
Definition: c.h:584
static void gistAddLoadedBuffer(GISTBuildBuffers *gfbb, GISTNodeBuffer *nodeBuffer)
#define offsetof(type, field)
Definition: c.h:551
void gistRelocateBuildBuffersOnSplit ( GISTBuildBuffers gfbb,
GISTSTATE giststate,
Relation  r,
int  level,
Buffer  buffer,
List splitinfo 
)

Definition at line 537 of file gistbuildbuffers.c.

References Assert, GISTNodeBuffer::blocksCount, GISTPageSplitInfo::buf, BufferGetBlockNumber(), GISTPageSplitInfo::downlink, RelocationBufferInfo::entry, GIST_ROOT_BLKNO, gistDeCompressAtt(), gistgetadjusted(), gistGetNodeBuffer(), gistpenalty(), gistPopItupFromNodeBuffer(), gistPushItupToNodeBuffer(), HASH_FIND, hash_search(), i, INDEX_MAX_KEYS, InvalidBlockNumber, RelocationBufferInfo::isnull, GISTNodeBuffer::isTemp, LEVEL_HAS_BUFFERS, lfirst, list_length(), tupleDesc::natts, RelocationBufferInfo::nodeBuffer, GISTBuildBuffers::nodeBuffersTab, NULL, GISTNodeBuffer::pageBlocknum, GISTNodeBuffer::pageBuffer, palloc(), pfree(), RelationData::rd_att, and RelocationBufferInfo::splitinfo.

Referenced by gistbufferinginserttuples().

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

Definition at line 1338 of file gist.c.

References Assert, SplitedPageLayout::block, check_stack_depth(), ereport, errcode(), errmsg(), ERROR, gistfillitupvec(), gistfitpage(), gistFormTuple(), GiSTPageSize, gistSplit(), gistSplitByKey(), i, IndexTupleSize, SplitedPageLayout::itup, SplitedPageLayout::lenlist, SplitedPageLayout::list, tupleDesc::natts, SplitedPageLayout::next, NULL, gistxlogPage::num, palloc(), 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, GistSplitVector::splitVector, TRUE, and GISTSTATE::tupdesc.

Referenced by gistplacetopage(), and gistSplit().

1343 {
1344  IndexTuple *lvectup,
1345  *rvectup;
1346  GistSplitVector v;
1347  int i;
1348  SplitedPageLayout *res = NULL;
1349 
1350  /* this should never recurse very deeply, but better safe than sorry */
1352 
1353  /* there's no point in splitting an empty page */
1354  Assert(len > 0);
1355 
1356  /*
1357  * If a single tuple doesn't fit on a page, no amount of splitting will
1358  * help.
1359  */
1360  if (len == 1)
1361  ereport(ERROR,
1362  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1363  errmsg("index row size %zu exceeds maximum %zu for index \"%s\"",
1364  IndexTupleSize(itup[0]), GiSTPageSize,
1366 
1367  memset(v.spl_lisnull, TRUE, sizeof(bool) * giststate->tupdesc->natts);
1368  memset(v.spl_risnull, TRUE, sizeof(bool) * giststate->tupdesc->natts);
1369  gistSplitByKey(r, page, itup, len, giststate, &v, 0);
1370 
1371  /* form left and right vector */
1372  lvectup = (IndexTuple *) palloc(sizeof(IndexTuple) * (len + 1));
1373  rvectup = (IndexTuple *) palloc(sizeof(IndexTuple) * (len + 1));
1374 
1375  for (i = 0; i < v.splitVector.spl_nleft; i++)
1376  lvectup[i] = itup[v.splitVector.spl_left[i] - 1];
1377 
1378  for (i = 0; i < v.splitVector.spl_nright; i++)
1379  rvectup[i] = itup[v.splitVector.spl_right[i] - 1];
1380 
1381  /* finalize splitting (may need another split) */
1382  if (!gistfitpage(rvectup, v.splitVector.spl_nright))
1383  {
1384  res = gistSplit(r, page, rvectup, v.splitVector.spl_nright, giststate);
1385  }
1386  else
1387  {
1388  ROTATEDIST(res);
1389  res->block.num = v.splitVector.spl_nright;
1390  res->list = gistfillitupvec(rvectup, v.splitVector.spl_nright, &(res->lenlist));
1391  res->itup = gistFormTuple(giststate, r, v.spl_rattr, v.spl_risnull, false);
1392  }
1393 
1394  if (!gistfitpage(lvectup, v.splitVector.spl_nleft))
1395  {
1396  SplitedPageLayout *resptr,
1397  *subres;
1398 
1399  resptr = subres = gistSplit(r, page, lvectup, v.splitVector.spl_nleft, giststate);
1400 
1401  /* install on list's tail */
1402  while (resptr->next)
1403  resptr = resptr->next;
1404 
1405  resptr->next = res;
1406  res = subres;
1407  }
1408  else
1409  {
1410  ROTATEDIST(res);
1411  res->block.num = v.splitVector.spl_nleft;
1412  res->list = gistfillitupvec(lvectup, v.splitVector.spl_nleft, &(res->lenlist));
1413  res->itup = gistFormTuple(giststate, r, v.spl_lattr, v.spl_lisnull, false);
1414  }
1415 
1416  return res;
1417 }
TupleDesc tupdesc
Definition: gist_private.h:81
Datum spl_lattr[INDEX_MAX_KEYS]
Definition: gist_private.h:228
OffsetNumber * spl_left
Definition: gist.h:105
GIST_SPLITVEC splitVector
Definition: gist_private.h:226
int errcode(int sqlerrcode)
Definition: elog.c:575
int spl_nleft
Definition: gist.h:106
IndexTupleData * list
Definition: gist_private.h:190
void gistSplitByKey(Relation r, Page page, IndexTuple *itup, int len, GISTSTATE *giststate, GistSplitVector *v, int attno)
Definition: gistsplit.c:623
Datum spl_rattr[INDEX_MAX_KEYS]
Definition: gist_private.h:232
int natts
Definition: tupdesc.h:73
gistxlogPage block
Definition: gist_private.h:189
#define ERROR
Definition: elog.h:43
int spl_nright
Definition: gist.h:111
void check_stack_depth(void)
Definition: postgres.c:3096
#define RelationGetRelationName(relation)
Definition: rel.h:433
struct SplitedPageLayout * next
Definition: gist_private.h:196
#define ereport(elevel, rest)
Definition: elog.h:122
#define GiSTPageSize
Definition: gist_private.h:432
#define ROTATEDIST(d)
Definition: gist.c:42
SplitedPageLayout * gistSplit(Relation r, Page page, IndexTuple *itup, int len, GISTSTATE *giststate)
Definition: gist.c:1338
bool gistfitpage(IndexTuple *itvec, int len)
Definition: gistutil.c:77
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
IndexTupleData * gistfillitupvec(IndexTuple *vec, int veclen, int *memlen)
Definition: gistutil.c:125
OffsetNumber * spl_right
Definition: gist.h:110
bool spl_risnull[INDEX_MAX_KEYS]
Definition: gist_private.h:234
void * palloc(Size size)
Definition: mcxt.c:891
int errmsg(const char *fmt,...)
Definition: elog.c:797
int i
IndexTuple gistFormTuple(GISTSTATE *giststate, Relation r, Datum attdata[], bool isnull[], bool isleaf)
Definition: gistutil.c:566
#define TRUE
Definition: c.h:214
bool spl_lisnull[INDEX_MAX_KEYS]
Definition: gist_private.h:230
#define IndexTupleSize(itup)
Definition: itup.h:70
void gistSplitByKey ( Relation  r,
Page  page,
IndexTuple itup,
int  len,
GISTSTATE giststate,
GistSplitVector v,
int  attno 
)

Definition at line 623 of file gistsplit.c.

References Assert, FALSE, GEVHDRSZ, gistdentryinit(), gistSplitByKey(), gistSplitHalf(), gistunionsubkey(), gistUserPicksplit(), i, index_getattr, GistEntryVector::n, tupleDesc::natts, NULL, palloc(), 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, GistSplitVector::splitVector, TRUE, GISTSTATE::tupdesc, and GistEntryVector::vector.

Referenced by gistSplit(), and gistSplitByKey().

625 {
626  GistEntryVector *entryvec;
627  OffsetNumber *offNullTuples;
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;
635  offNullTuples = (OffsetNumber *) palloc(len * sizeof(OffsetNumber));
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->tupdesc,
643  &IsNull);
644  gistdentryinit(giststate, attno, &(entryvec->vector[i]),
645  datum, r, page, i,
646  FALSE, IsNull);
647  if (IsNull)
648  offNullTuples[nOffNullTuples++] = i;
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->tupdesc->natts)
661  gistSplitByKey(r, page, itup, len, giststate, v, attno + 1);
662  else
663  gistSplitHalf(&v->splitVector, len);
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  */
673  v->splitVector.spl_right = offNullTuples;
674  v->splitVector.spl_nright = nOffNullTuples;
675  v->spl_risnull[attno] = TRUE;
676 
677  v->splitVector.spl_left = (OffsetNumber *) palloc(len * sizeof(OffsetNumber));
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->tupdesc->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->tupdesc->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  */
719  IndexTuple *newitup = (IndexTuple *) palloc(len * sizeof(IndexTuple));
720  OffsetNumber *map = (OffsetNumber *) palloc(len * sizeof(OffsetNumber));
721  int newlen = 0;
722  GIST_SPLITVEC backupSplit;
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  */
740  backupSplit = v->splitVector;
741  backupSplit.spl_left = (OffsetNumber *) palloc(sizeof(OffsetNumber) * len);
742  memcpy(backupSplit.spl_left, v->splitVector.spl_left, sizeof(OffsetNumber) * v->splitVector.spl_nleft);
743  backupSplit.spl_right = (OffsetNumber *) palloc(sizeof(OffsetNumber) * len);
744  memcpy(backupSplit.spl_right, v->splitVector.spl_right, sizeof(OffsetNumber) * v->splitVector.spl_nright);
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 
755  v->splitVector = backupSplit;
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->tupdesc->natts > 1)
775  {
776  v->spl_dontcare = NULL;
777  gistunionsubkey(giststate, itup, v);
778  }
779 }
TupleDesc tupdesc
Definition: gist_private.h:81
OffsetNumber * spl_left
Definition: gist.h:105
GIST_SPLITVEC splitVector
Definition: gist_private.h:226
int32 n
Definition: gist.h:160
int spl_nleft
Definition: gist.h:106
void gistSplitByKey(Relation r, Page page, IndexTuple *itup, int len, GISTSTATE *giststate, GistSplitVector *v, int attno)
Definition: gistsplit.c:623
int natts
Definition: tupdesc.h:73
uint16 OffsetNumber
Definition: off.h:24
GISTENTRY vector[FLEXIBLE_ARRAY_MEMBER]
Definition: gist.h:161
#define GEVHDRSZ
Definition: gist.h:164
void gistdentryinit(GISTSTATE *giststate, int nkey, GISTENTRY *e, Datum k, Relation r, Page pg, OffsetNumber o, bool l, bool isNull)
Definition: gistutil.c:543
#define FALSE
Definition: c.h:218
int spl_nright
Definition: gist.h:111
uintptr_t Datum
Definition: postgres.h:374
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
static void gistSplitHalf(GIST_SPLITVEC *v, int len)
Definition: gistsplit.c:585
OffsetNumber * spl_right
Definition: gist.h:110
#define index_getattr(tup, attnum, tupleDesc, isnull)
Definition: itup.h:100
bool spl_risnull[INDEX_MAX_KEYS]
Definition: gist_private.h:234
void * palloc(Size size)
Definition: mcxt.c:891
int i
static void gistunionsubkey(GISTSTATE *giststate, IndexTuple *itvec, GistSplitVector *spl)
Definition: gistsplit.c:80
#define TRUE
Definition: c.h:214
bool spl_lisnull[INDEX_MAX_KEYS]
Definition: gist_private.h:230
static bool gistUserPicksplit(Relation r, GistEntryVector *entryvec, int attno, GistSplitVector *v, IndexTuple *itup, int len, GISTSTATE *giststate)
Definition: gistsplit.c:415
IndexTuple gistunion ( Relation  r,
IndexTuple itvec,
int  len,
GISTSTATE giststate 
)

Definition at line 216 of file gistutil.c.

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

217 {
218  Datum attr[INDEX_MAX_KEYS];
219  bool isnull[INDEX_MAX_KEYS];
220 
221  gistMakeUnionItVec(giststate, itvec, len, attr, isnull);
222 
223  return gistFormTuple(giststate, r, attr, isnull, false);
224 }
uintptr_t Datum
Definition: postgres.h:374
void gistMakeUnionItVec(GISTSTATE *giststate, IndexTuple *itvec, int len, Datum *attr, bool *isnull)
Definition: gistutil.c:153
#define INDEX_MAX_KEYS
IndexTuple gistFormTuple(GISTSTATE *giststate, Relation r, Datum attdata[], bool isnull[], bool isleaf)
Definition: gistutil.c:566
void gistUnloadNodeBuffers ( GISTBuildBuffers gfbb)

Definition at line 276 of file gistbuildbuffers.c.

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

Referenced by gistProcessEmptyingQueue().

277 {
278  int i;
279 
280  /* Unload all the buffers that have a page loaded in memory. */
281  for (i = 0; i < gfbb->loadedBuffersCount; i++)
282  gistUnloadNodeBuffer(gfbb, gfbb->loadedBuffers[i]);
283 
284  /* Now there are no node buffers with loaded last page */
285  gfbb->loadedBuffersCount = 0;
286 }
static void gistUnloadNodeBuffer(GISTBuildBuffers *gfbb, GISTNodeBuffer *nodeBuffer)
GISTNodeBuffer ** loadedBuffers
Definition: gist_private.h:362
int i
IndexBulkDeleteResult* gistvacuumcleanup ( IndexVacuumInfo info,
IndexBulkDeleteResult stats 
)

Definition at line 29 of file gistvacuum.c.

References IndexVacuumInfo::analyze_only, DataPageDeleteStack::blkno, BufferGetPage, IndexVacuumInfo::estimated_count, IndexBulkDeleteResult::estimated_count, ExclusiveLock, GIST_ROOT_BLKNO, GIST_SHARE, GistPageIsDeleted, IndexVacuumInfo::index, IndexFreeSpaceMapVacuum(), LockBuffer(), LockRelationForExtension(), MAIN_FORKNUM, NULL, IndexVacuumInfo::num_heap_tuples, IndexBulkDeleteResult::num_index_tuples, IndexBulkDeleteResult::num_pages, PageIsNew, IndexBulkDeleteResult::pages_free, palloc0(), RBM_NORMAL, ReadBufferExtended(), RecordFreeIndexPage(), RELATION_IS_LOCAL, RelationGetNumberOfBlocks, IndexVacuumInfo::strategy, UnlockRelationForExtension(), UnlockReleaseBuffer(), and vacuum_delay_point().

Referenced by gisthandler().

30 {
31  Relation rel = info->index;
32  BlockNumber npages,
33  blkno;
34  BlockNumber totFreePages;
35  bool needLock;
36 
37  /* No-op in ANALYZE ONLY mode */
38  if (info->analyze_only)
39  return stats;
40 
41  /* Set up all-zero stats if gistbulkdelete wasn't called */
42  if (stats == NULL)
43  {
45  /* use heap's tuple count */
46  stats->num_index_tuples = info->num_heap_tuples;
47  stats->estimated_count = info->estimated_count;
48 
49  /*
50  * XXX the above is wrong if index is partial. Would it be OK to just
51  * return NULL, or is there work we must do below?
52  */
53  }
54 
55  /*
56  * Need lock unless it's local to this backend.
57  */
58  needLock = !RELATION_IS_LOCAL(rel);
59 
60  /* try to find deleted pages */
61  if (needLock)
63  npages = RelationGetNumberOfBlocks(rel);
64  if (needLock)
66 
67  totFreePages = 0;
68  for (blkno = GIST_ROOT_BLKNO + 1; blkno < npages; blkno++)
69  {
70  Buffer buffer;
71  Page page;
72 
74 
75  buffer = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL,
76  info->strategy);
77  LockBuffer(buffer, GIST_SHARE);
78  page = (Page) BufferGetPage(buffer);
79 
80  if (PageIsNew(page) || GistPageIsDeleted(page))
81  {
82  totFreePages++;
83  RecordFreeIndexPage(rel, blkno);
84  }
85  UnlockReleaseBuffer(buffer);
86  }
87 
88  /* Finally, vacuum the FSM */
90 
91  /* return statistics */
92  stats->pages_free = totFreePages;
93  if (needLock)
96  if (needLock)
98 
99  return stats;
100 }
#define GistPageIsDeleted(page)
Definition: gist.h:135
#define ExclusiveLock
Definition: lockdefs.h:44
#define RELATION_IS_LOCAL(relation)
Definition: rel.h:520
bool analyze_only
Definition: genam.h:47
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition: bufmgr.c:640
BufferAccessStrategy strategy
Definition: genam.h:51
Relation index
Definition: genam.h:46
uint32 BlockNumber
Definition: block.h:31
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3315
BlockNumber num_pages
Definition: genam.h:73
BlockNumber pages_free
Definition: genam.h:79
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
void LockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition: lmgr.c:332
void * palloc0(Size size)
Definition: mcxt.c:920
void UnlockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition: lmgr.c:382
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3529
#define RelationGetNumberOfBlocks(reln)
Definition: bufmgr.h:199
double num_heap_tuples
Definition: genam.h:50
#define NULL
Definition: c.h:226
void IndexFreeSpaceMapVacuum(Relation rel)
Definition: indexfsm.c:71
#define GIST_SHARE
Definition: gist_private.h:43
#define PageIsNew(page)
Definition: bufpage.h:226
#define GIST_ROOT_BLKNO
Definition: gist_private.h:249
void vacuum_delay_point(void)
Definition: vacuum.c:1515
void RecordFreeIndexPage(Relation rel, BlockNumber freeBlock)
Definition: indexfsm.c:52
double num_index_tuples
Definition: genam.h:76
int Buffer
Definition: buf.h:23
bool estimated_count
Definition: genam.h:75
Pointer Page
Definition: bufpage.h:74
bool estimated_count
Definition: genam.h:48
bool gistvalidate ( Oid  opclassoid)

Definition at line 34 of file gistvalidate.c.

References AMOP_SEARCH, AMOPSTRATEGY, AMPROCNUM, BOOLOID, check_amop_signature(), check_amproc_signature(), CLAOID, elog, ereport, errcode(), errmsg(), ERROR, FLOAT8OID, format_operator(), format_procedure(), OpFamilyOpFuncGroup::functionset, get_op_rettype(), get_opfamily_proc(), GETSTRUCT, 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, GISTNProcs, HeapTupleIsValid, i, identify_opfamily_groups(), INFO, INT2OID, INTERNALOID, OpFamilyOpFuncGroup::lefttype, lfirst, catclist::members, catclist::n_members, NameStr, NULL, ObjectIdGetDatum, OidIsValid, OIDOID, opfamily_can_sort_type(), OPFAMILYOID, ReleaseCatCacheList(), ReleaseSysCache(), OpFamilyOpFuncGroup::righttype, SearchSysCache1, SearchSysCacheList1, and catctup::tuple.

Referenced by gisthandler().

35 {
36  bool result = true;
37  HeapTuple classtup;
38  Form_pg_opclass classform;
39  Oid opfamilyoid;
40  Oid opcintype;
41  Oid opckeytype;
42  char *opclassname;
43  HeapTuple familytup;
44  Form_pg_opfamily familyform;
45  char *opfamilyname;
46  CatCList *proclist,
47  *oprlist;
48  List *grouplist;
49  OpFamilyOpFuncGroup *opclassgroup;
50  int i;
51  ListCell *lc;
52 
53  /* Fetch opclass information */
54  classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
55  if (!HeapTupleIsValid(classtup))
56  elog(ERROR, "cache lookup failed for operator class %u", opclassoid);
57  classform = (Form_pg_opclass) GETSTRUCT(classtup);
58 
59  opfamilyoid = classform->opcfamily;
60  opcintype = classform->opcintype;
61  opckeytype = classform->opckeytype;
62  if (!OidIsValid(opckeytype))
63  opckeytype = opcintype;
64  opclassname = NameStr(classform->opcname);
65 
66  /* Fetch opfamily information */
67  familytup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfamilyoid));
68  if (!HeapTupleIsValid(familytup))
69  elog(ERROR, "cache lookup failed for operator family %u", opfamilyoid);
70  familyform = (Form_pg_opfamily) GETSTRUCT(familytup);
71 
72  opfamilyname = NameStr(familyform->opfname);
73 
74  /* Fetch all operators and support functions of the opfamily */
75  oprlist = SearchSysCacheList1(AMOPSTRATEGY, ObjectIdGetDatum(opfamilyoid));
76  proclist = SearchSysCacheList1(AMPROCNUM, ObjectIdGetDatum(opfamilyoid));
77 
78  /* Check individual support functions */
79  for (i = 0; i < proclist->n_members; i++)
80  {
81  HeapTuple proctup = &proclist->members[i]->tuple;
82  Form_pg_amproc procform = (Form_pg_amproc) GETSTRUCT(proctup);
83  bool ok;
84 
85  /*
86  * All GiST support functions should be registered with matching
87  * left/right types
88  */
89  if (procform->amproclefttype != procform->amprocrighttype)
90  {
91  ereport(INFO,
92  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
93  errmsg("gist operator family \"%s\" contains support procedure %s with cross-type registration",
94  opfamilyname,
95  format_procedure(procform->amproc))));
96  result = false;
97  }
98 
99  /*
100  * We can't check signatures except within the specific opclass, since
101  * we need to know the associated opckeytype in many cases.
102  */
103  if (procform->amproclefttype != opcintype)
104  continue;
105 
106  /* Check procedure numbers and function signatures */
107  switch (procform->amprocnum)
108  {
110  ok = check_amproc_signature(procform->amproc, BOOLOID, false,
111  5, 5, INTERNALOID, opcintype,
113  break;
114  case GIST_UNION_PROC:
115  ok = check_amproc_signature(procform->amproc, opckeytype, false,
116  2, 2, INTERNALOID, INTERNALOID);
117  break;
118  case GIST_COMPRESS_PROC:
120  case GIST_FETCH_PROC:
121  ok = check_amproc_signature(procform->amproc, INTERNALOID, true,
122  1, 1, INTERNALOID);
123  break;
124  case GIST_PENALTY_PROC:
125  ok = check_amproc_signature(procform->amproc, INTERNALOID, true,
126  3, 3, INTERNALOID,
128  break;
129  case GIST_PICKSPLIT_PROC:
130  ok = check_amproc_signature(procform->amproc, INTERNALOID, true,
131  2, 2, INTERNALOID, INTERNALOID);
132  break;
133  case GIST_EQUAL_PROC:
134  ok = check_amproc_signature(procform->amproc, INTERNALOID, false,
135  3, 3, opckeytype, opckeytype,
136  INTERNALOID);
137  break;
138  case GIST_DISTANCE_PROC:
139  ok = check_amproc_signature(procform->amproc, FLOAT8OID, false,
140  5, 5, INTERNALOID, opcintype,
142  break;
143  default:
144  ereport(INFO,
145  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
146  errmsg("gist operator family \"%s\" contains function %s with invalid support number %d",
147  opfamilyname,
148  format_procedure(procform->amproc),
149  procform->amprocnum)));
150  result = false;
151  continue; /* don't want additional message */
152  }
153 
154  if (!ok)
155  {
156  ereport(INFO,
157  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
158  errmsg("gist operator family \"%s\" contains function %s with wrong signature for support number %d",
159  opfamilyname,
160  format_procedure(procform->amproc),
161  procform->amprocnum)));
162  result = false;
163  }
164  }
165 
166  /* Check individual operators */
167  for (i = 0; i < oprlist->n_members; i++)
168  {
169  HeapTuple oprtup = &oprlist->members[i]->tuple;
170  Form_pg_amop oprform = (Form_pg_amop) GETSTRUCT(oprtup);
171  Oid op_rettype;
172 
173  /* TODO: Check that only allowed strategy numbers exist */
174  if (oprform->amopstrategy < 1)
175  {
176  ereport(INFO,
177  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
178  errmsg("gist operator family \"%s\" contains operator %s with invalid strategy number %d",
179  opfamilyname,
180  format_operator(oprform->amopopr),
181  oprform->amopstrategy)));
182  result = false;
183  }
184 
185  /* GiST supports ORDER BY operators */
186  if (oprform->amoppurpose != AMOP_SEARCH)
187  {
188  /* ... but must have matching distance proc */
189  if (!OidIsValid(get_opfamily_proc(opfamilyoid,
190  oprform->amoplefttype,
191  oprform->amoplefttype,
193  {
194  ereport(INFO,
195  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
196  errmsg("gist operator family \"%s\" contains unsupported ORDER BY specification for operator %s",
197  opfamilyname,
198  format_operator(oprform->amopopr))));
199  result = false;
200  }
201  /* ... and operator result must match the claimed btree opfamily */
202  op_rettype = get_op_rettype(oprform->amopopr);
203  if (!opfamily_can_sort_type(oprform->amopsortfamily, op_rettype))
204  {
205  ereport(INFO,
206  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
207  errmsg("gist operator family \"%s\" contains incorrect ORDER BY opfamily specification for operator %s",
208  opfamilyname,
209  format_operator(oprform->amopopr))));
210  result = false;
211  }
212  }
213  else
214  {
215  /* Search operators must always return bool */
216  op_rettype = BOOLOID;
217  }
218 
219  /* Check operator signature */
220  if (!check_amop_signature(oprform->amopopr, op_rettype,
221  oprform->amoplefttype,
222  oprform->amoprighttype))
223  {
224  ereport(INFO,
225  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
226  errmsg("gist operator family \"%s\" contains operator %s with wrong signature",
227  opfamilyname,
228  format_operator(oprform->amopopr))));
229  result = false;
230  }
231  }
232 
233  /* Now check for inconsistent groups of operators/functions */
234  grouplist = identify_opfamily_groups(oprlist, proclist);
235  opclassgroup = NULL;
236  foreach(lc, grouplist)
237  {
238  OpFamilyOpFuncGroup *thisgroup = (OpFamilyOpFuncGroup *) lfirst(lc);
239 
240  /* Remember the group exactly matching the test opclass */
241  if (thisgroup->lefttype == opcintype &&
242  thisgroup->righttype == opcintype)
243  opclassgroup = thisgroup;
244 
245  /*
246  * There is not a lot we can do to check the operator sets, since each
247  * GiST opclass is more or less a law unto itself, and some contain
248  * only operators that are binary-compatible with the opclass datatype
249  * (meaning that empty operator sets can be OK). That case also means
250  * that we shouldn't insist on nonempty function sets except for the
251  * opclass's own group.
252  */
253  }
254 
255  /* Check that the originally-named opclass is complete */
256  for (i = 1; i <= GISTNProcs; i++)
257  {
258  if (opclassgroup &&
259  (opclassgroup->functionset & (((uint64) 1) << i)) != 0)
260  continue; /* got it */
261  if (i == GIST_DISTANCE_PROC || i == GIST_FETCH_PROC)
262  continue; /* optional methods */
263  ereport(INFO,
264  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
265  errmsg("gist operator class \"%s\" is missing support function %d",
266  opclassname, i)));
267  result = false;
268  }
269 
270  ReleaseCatCacheList(proclist);
271  ReleaseCatCacheList(oprlist);
272  ReleaseSysCache(familytup);
273  ReleaseSysCache(classtup);
274 
275  return result;
276 }
int n_members
Definition: catcache.h:154
#define GIST_FETCH_PROC
Definition: gist.h:36
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
bool opfamily_can_sort_type(Oid opfamilyoid, Oid datatypeoid)
Definition: amvalidate.c:217
#define AMOP_SEARCH
Definition: pg_amop.h:69
#define OIDOID
Definition: pg_type.h:328
#define GIST_EQUAL_PROC
Definition: gist.h:34
FormData_pg_amproc * Form_pg_amproc
Definition: pg_amproc.h:59
int errcode(int sqlerrcode)
Definition: elog.c:575
#define INFO
Definition: elog.h:33
char * format_operator(Oid operator_oid)
Definition: regproc.c:904
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:534
Oid get_op_rettype(Oid opno)
Definition: lsyscache.c:1110
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:149
void ReleaseCatCacheList(CatCList *list)
Definition: catcache.c:1665
CatCTup * members[FLEXIBLE_ARRAY_MEMBER]
Definition: catcache.h:155
bool check_amproc_signature(Oid funcid, Oid restype, bool exact, int minargs, int maxargs,...)
Definition: amvalidate.c:150
#define GIST_PICKSPLIT_PROC
Definition: gist.h:33
#define ObjectIdGetDatum(X)
Definition: postgres.h:515
#define ERROR
Definition: elog.h:43
#define GIST_COMPRESS_PROC
Definition: gist.h:30
List * identify_opfamily_groups(CatCList *oprlist, CatCList *proclist)
Definition: amvalidate.c:41
#define INT2OID
Definition: pg_type.h:308
#define SearchSysCacheList1(cacheId, key1)
Definition: syscache.h:194
#define ereport(elevel, rest)
Definition: elog.h:122
FormData_pg_opfamily * Form_pg_opfamily
Definition: pg_opfamily.h:44
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1083
#define INTERNALOID
Definition: pg_type.h:686
#define GIST_CONSISTENT_PROC
Definition: gist.h:28
char * format_procedure(Oid procedure_oid)
Definition: regproc.c:367
#define GIST_UNION_PROC
Definition: gist.h:29
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:226
#define lfirst(lc)
Definition: pg_list.h:106
Oid get_opfamily_proc(Oid opfamily, Oid lefttype, Oid righttype, int16 procnum)
Definition: lsyscache.c:744
#define GIST_PENALTY_PROC
Definition: gist.h:32
#define FLOAT8OID
Definition: pg_type.h:411
#define GIST_DISTANCE_PROC
Definition: gist.h:35
bool check_amop_signature(Oid opno, Oid restype, Oid lefttype, Oid righttype)
Definition: amvalidate.c:194
#define BOOLOID
Definition: pg_type.h:288
#define GISTNProcs
Definition: gist.h:37
int errmsg(const char *fmt,...)
Definition: elog.c:797
FormData_pg_amop * Form_pg_amop
Definition: pg_amop.h:77
in