PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
spginsert.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * spginsert.c
4  * Externally visible index creation/insertion routines
5  *
6  * All the actual insertion logic is in spgdoinsert.c.
7  *
8  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
9  * Portions Copyright (c) 1994, Regents of the University of California
10  *
11  * IDENTIFICATION
12  * src/backend/access/spgist/spginsert.c
13  *
14  *-------------------------------------------------------------------------
15  */
16 
17 #include "postgres.h"
18 
19 #include "access/genam.h"
20 #include "access/spgist_private.h"
21 #include "access/spgxlog.h"
22 #include "access/xlog.h"
23 #include "access/xloginsert.h"
24 #include "catalog/index.h"
25 #include "miscadmin.h"
26 #include "storage/bufmgr.h"
27 #include "storage/smgr.h"
28 #include "utils/memutils.h"
29 #include "utils/rel.h"
30 
31 
32 typedef struct
33 {
34  SpGistState spgstate; /* SPGiST's working state */
35  MemoryContext tmpCtx; /* per-tuple temporary context */
37 
38 
39 /* Callback to process one heap tuple during IndexBuildHeapScan */
40 static void
42  bool *isnull, bool tupleIsAlive, void *state)
43 {
44  SpGistBuildState *buildstate = (SpGistBuildState *) state;
45  MemoryContext oldCtx;
46 
47  /* Work in temp context, and reset it after each tuple */
48  oldCtx = MemoryContextSwitchTo(buildstate->tmpCtx);
49 
50  /*
51  * Even though no concurrent insertions can be happening, we still might
52  * get a buffer-locking failure due to bgwriter or checkpointer taking a
53  * lock on some buffer. So we need to be willing to retry. We can flush
54  * any temp data when retrying.
55  */
56  while (!spgdoinsert(index, &buildstate->spgstate, &htup->t_self,
57  *values, *isnull))
58  {
59  MemoryContextReset(buildstate->tmpCtx);
60  }
61 
62  MemoryContextSwitchTo(oldCtx);
63  MemoryContextReset(buildstate->tmpCtx);
64 }
65 
66 /*
67  * Build an SP-GiST index.
68  */
71 {
72  IndexBuildResult *result;
73  double reltuples;
74  SpGistBuildState buildstate;
75  Buffer metabuffer,
76  rootbuffer,
77  nullbuffer;
78 
79  if (RelationGetNumberOfBlocks(index) != 0)
80  elog(ERROR, "index \"%s\" already contains data",
82 
83  /*
84  * Initialize the meta page and root pages
85  */
86  metabuffer = SpGistNewBuffer(index);
87  rootbuffer = SpGistNewBuffer(index);
88  nullbuffer = SpGistNewBuffer(index);
89 
93 
95 
96  SpGistInitMetapage(BufferGetPage(metabuffer));
97  MarkBufferDirty(metabuffer);
98  SpGistInitBuffer(rootbuffer, SPGIST_LEAF);
99  MarkBufferDirty(rootbuffer);
101  MarkBufferDirty(nullbuffer);
102 
103  if (RelationNeedsWAL(index))
104  {
105  XLogRecPtr recptr;
106 
107  XLogBeginInsert();
108 
109  /*
110  * Replay will re-initialize the pages, so don't take full pages
111  * images. No other data to log.
112  */
113  XLogRegisterBuffer(0, metabuffer, REGBUF_WILL_INIT);
116 
117  recptr = XLogInsert(RM_SPGIST_ID, XLOG_SPGIST_CREATE_INDEX);
118 
119  PageSetLSN(BufferGetPage(metabuffer), recptr);
120  PageSetLSN(BufferGetPage(rootbuffer), recptr);
121  PageSetLSN(BufferGetPage(nullbuffer), recptr);
122  }
123 
125 
126  UnlockReleaseBuffer(metabuffer);
127  UnlockReleaseBuffer(rootbuffer);
128  UnlockReleaseBuffer(nullbuffer);
129 
130  /*
131  * Now insert all the heap data into the index
132  */
133  initSpGistState(&buildstate.spgstate, index);
134  buildstate.spgstate.isBuild = true;
135 
137  "SP-GiST build temporary context",
139 
140  reltuples = IndexBuildHeapScan(heap, index, indexInfo, true,
141  spgistBuildCallback, (void *) &buildstate);
142 
143  MemoryContextDelete(buildstate.tmpCtx);
144 
145  SpGistUpdateMetaPage(index);
146 
147  result = (IndexBuildResult *) palloc0(sizeof(IndexBuildResult));
148  result->heap_tuples = result->index_tuples = reltuples;
149 
150  return result;
151 }
152 
153 /*
154  * Build an empty SPGiST index in the initialization fork
155  */
156 void
158 {
159  Page page;
160 
161  /* Construct metapage. */
162  page = (Page) palloc(BLCKSZ);
163  SpGistInitMetapage(page);
164 
165  /*
166  * Write the page and log it unconditionally. This is important
167  * particularly for indexes created on tablespaces and databases whose
168  * creation happened after the last redo pointer as recovery removes any
169  * of their existing content when the corresponding create records are
170  * replayed.
171  */
174  (char *) page, true);
176  SPGIST_METAPAGE_BLKNO, page, false);
177 
178  /* Likewise for the root page. */
180 
183  (char *) page, true);
185  SPGIST_ROOT_BLKNO, page, true);
186 
187  /* Likewise for the null-tuples root page. */
189 
192  (char *) page, true);
194  SPGIST_NULL_BLKNO, page, true);
195 
196  /*
197  * An immediate sync is required even if we xlog'd the pages, because the
198  * writes did not go through shared buffers and therefore a concurrent
199  * checkpoint may have moved the redo pointer past our xlog record.
200  */
202 }
203 
204 /*
205  * Insert one new tuple into an SPGiST index.
206  */
207 bool
209  ItemPointer ht_ctid, Relation heapRel,
210  IndexUniqueCheck checkUnique,
211  IndexInfo *indexInfo)
212 {
213  SpGistState spgstate;
214  MemoryContext oldCtx;
215  MemoryContext insertCtx;
216 
218  "SP-GiST insert temporary context",
220  oldCtx = MemoryContextSwitchTo(insertCtx);
221 
222  initSpGistState(&spgstate, index);
223 
224  /*
225  * We might have to repeat spgdoinsert() multiple times, if conflicts
226  * occur with concurrent insertions. If so, reset the insertCtx each time
227  * to avoid cumulative memory consumption. That means we also have to
228  * redo initSpGistState(), but it's cheap enough not to matter.
229  */
230  while (!spgdoinsert(index, &spgstate, ht_ctid, *values, *isnull))
231  {
232  MemoryContextReset(insertCtx);
233  initSpGistState(&spgstate, index);
234  }
235 
236  SpGistUpdateMetaPage(index);
237 
238  MemoryContextSwitchTo(oldCtx);
239  MemoryContextDelete(insertCtx);
240 
241  /* return false since we've not done any unique check */
242  return false;
243 }
void SpGistUpdateMetaPage(Relation index)
Definition: spgutils.c:252
bool spgdoinsert(Relation index, SpGistState *state, ItemPointer heapPtr, Datum datum, bool isnull)
Definition: spgdoinsert.c:1891
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:200
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1450
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:213
struct SMgrRelationData * rd_smgr
Definition: rel.h:87
#define END_CRIT_SECTION()
Definition: miscadmin.h:133
#define SPGIST_NULLS
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define REGBUF_WILL_INIT
Definition: xloginsert.h:32
#define START_CRIT_SECTION()
Definition: miscadmin.h:131
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:135
bool spginsert(Relation index, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, IndexUniqueCheck checkUnique, IndexInfo *indexInfo)
Definition: spginsert.c:208
SpGistState spgstate
Definition: spginsert.c:34
#define SPGIST_ROOT_BLKNO
Definition: type.h:89
IndexUniqueCheck
Definition: genam.h:111
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
#define ERROR
Definition: elog.h:43
#define XLOG_SPGIST_CREATE_INDEX
Definition: spgxlog.h:21
ItemPointerData t_self
Definition: htup.h:65
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:165
RelFileNodeBackend smgr_rnode
Definition: smgr.h:43
#define SPGIST_NULL_BLKNO
void smgrwrite(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum, char *buffer, bool skipFsync)
Definition: smgr.c:647
#define REGBUF_STANDARD
Definition: xloginsert.h:34
#define SPGIST_METAPAGE_BLKNO
void initSpGistState(SpGistState *state, Relation index)
Definition: spgutils.c:158
#define RelationGetRelationName(relation)
Definition: rel.h:436
static void spgistBuildCallback(Relation index, HeapTuple htup, Datum *values, bool *isnull, bool tupleIsAlive, void *state)
Definition: spginsert.c:41
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
void spgbuildempty(Relation index)
Definition: spginsert.c:157
void SpGistInitBuffer(Buffer b, uint16 f)
Definition: spgutils.c:514
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:322
void * palloc0(Size size)
Definition: mcxt.c:877
uintptr_t Datum
Definition: postgres.h:372
#define RelationGetNumberOfBlocks(reln)
Definition: bufmgr.h:199
Buffer SpGistNewBuffer(Relation index)
Definition: spgutils.c:187
RelFileNode node
Definition: relfilenode.h:74
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:681
Definition: regguts.h:298
void SpGistInitMetapage(Page page)
Definition: spgutils.c:524
void PageSetChecksumInplace(Page page, BlockNumber blkno)
Definition: bufpage.c:1199
#define RelationNeedsWAL(relation)
Definition: rel.h:505
IndexBuildResult * spgbuild(Relation heap, Relation index, IndexInfo *indexInfo)
Definition: spginsert.c:70
static Datum values[MAXATTR]
Definition: bootstrap.c:164
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2605
double IndexBuildHeapScan(Relation heapRelation, Relation indexRelation, IndexInfo *indexInfo, bool allow_sync, IndexBuildCallback callback, void *callback_state)
Definition: index.c:2175
void SpGistInitPage(Page page, uint16 f)
Definition: spgutils.c:499
void * palloc(Size size)
Definition: mcxt.c:848
XLogRecPtr log_newpage(RelFileNode *rnode, ForkNumber forkNum, BlockNumber blkno, Page page, bool page_std)
Definition: xloginsert.c:972
MemoryContext tmpCtx
Definition: spginsert.c:35
#define elog
Definition: elog.h:219
void XLogBeginInsert(void)
Definition: xloginsert.c:120
#define SPGIST_LEAF
#define PageSetLSN(page, lsn)
Definition: bufpage.h:364
int Buffer
Definition: buf.h:23
void smgrimmedsync(SMgrRelation reln, ForkNumber forknum)
Definition: smgr.c:734
Pointer Page
Definition: bufpage.h:74
double index_tuples
Definition: genam.h:33
double heap_tuples
Definition: genam.h:32