PostgreSQL Source Code git master
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-2025, 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"
21#include "access/tableam.h"
22#include "access/xloginsert.h"
23#include "miscadmin.h"
24#include "nodes/execnodes.h"
25#include "storage/bufmgr.h"
26#include "storage/bulk_write.h"
27#include "utils/memutils.h"
28#include "utils/rel.h"
29
30
31typedef struct
32{
33 SpGistState spgstate; /* SPGiST's working state */
34 int64 indtuples; /* total number of tuples indexed */
35 MemoryContext tmpCtx; /* per-tuple temporary context */
37
38
39/* Callback to process one heap tuple during table_index_build_scan */
40static 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, tid,
57 values, isnull))
58 {
59 MemoryContextReset(buildstate->tmpCtx);
60 }
61
62 /* Update total tuple count */
63 buildstate->indtuples += 1;
64
66 MemoryContextReset(buildstate->tmpCtx);
67}
68
69/*
70 * Build an SP-GiST index.
71 */
74{
75 IndexBuildResult *result;
76 double reltuples;
77 SpGistBuildState buildstate;
78 Buffer metabuffer,
79 rootbuffer,
80 nullbuffer;
81
83 elog(ERROR, "index \"%s\" already contains data",
85
86 /*
87 * Initialize the meta page and root pages
88 */
89 metabuffer = SpGistNewBuffer(index);
90 rootbuffer = SpGistNewBuffer(index);
91 nullbuffer = SpGistNewBuffer(index);
92
96
98
100 MarkBufferDirty(metabuffer);
101 SpGistInitBuffer(rootbuffer, SPGIST_LEAF);
102 MarkBufferDirty(rootbuffer);
104 MarkBufferDirty(nullbuffer);
105
106
108
109 UnlockReleaseBuffer(metabuffer);
110 UnlockReleaseBuffer(rootbuffer);
111 UnlockReleaseBuffer(nullbuffer);
112
113 /*
114 * Now insert all the heap data into the index
115 */
116 initSpGistState(&buildstate.spgstate, index);
117 buildstate.spgstate.isBuild = true;
118 buildstate.indtuples = 0;
119
121 "SP-GiST build temporary context",
123
124 reltuples = table_index_build_scan(heap, index, indexInfo, true, true,
125 spgistBuildCallback, &buildstate,
126 NULL);
127
128 MemoryContextDelete(buildstate.tmpCtx);
129
131
132 /*
133 * We didn't write WAL records as we built the index, so if WAL-logging is
134 * required, write all pages to the WAL now.
135 */
137 {
140 true);
141 }
142
143 result = (IndexBuildResult *) palloc0(sizeof(IndexBuildResult));
144 result->heap_tuples = reltuples;
145 result->index_tuples = buildstate.indtuples;
146
147 return result;
148}
149
150/*
151 * Build an empty SPGiST index in the initialization fork
152 */
153void
155{
156 BulkWriteState *bulkstate;
158
160
161 /* Construct metapage. */
162 buf = smgr_bulk_get_buf(bulkstate);
164 smgr_bulk_write(bulkstate, SPGIST_METAPAGE_BLKNO, buf, true);
165
166 /* Likewise for the root page. */
167 buf = smgr_bulk_get_buf(bulkstate);
169 smgr_bulk_write(bulkstate, SPGIST_ROOT_BLKNO, buf, true);
170
171 /* Likewise for the null-tuples root page. */
172 buf = smgr_bulk_get_buf(bulkstate);
174 smgr_bulk_write(bulkstate, SPGIST_NULL_BLKNO, buf, true);
175
176 smgr_bulk_finish(bulkstate);
177}
178
179/*
180 * Insert one new tuple into an SPGiST index.
181 */
182bool
184 ItemPointer ht_ctid, Relation heapRel,
185 IndexUniqueCheck checkUnique,
186 bool indexUnchanged,
187 IndexInfo *indexInfo)
188{
189 SpGistState spgstate;
190 MemoryContext oldCtx;
191 MemoryContext insertCtx;
192
194 "SP-GiST insert temporary context",
196 oldCtx = MemoryContextSwitchTo(insertCtx);
197
198 initSpGistState(&spgstate, index);
199
200 /*
201 * We might have to repeat spgdoinsert() multiple times, if conflicts
202 * occur with concurrent insertions. If so, reset the insertCtx each time
203 * to avoid cumulative memory consumption. That means we also have to
204 * redo initSpGistState(), but it's cheap enough not to matter.
205 */
206 while (!spgdoinsert(index, &spgstate, ht_ctid, values, isnull))
207 {
208 MemoryContextReset(insertCtx);
209 initSpGistState(&spgstate, index);
210 }
211
213
214 MemoryContextSwitchTo(oldCtx);
215 MemoryContextDelete(insertCtx);
216
217 /* return false since we've not done any unique check */
218 return false;
219}
static Datum values[MAXATTR]
Definition: bootstrap.c:151
int Buffer
Definition: buf.h:23
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:3724
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:4883
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:2532
#define RelationGetNumberOfBlocks(reln)
Definition: bufmgr.h:273
static Page BufferGetPage(Buffer buffer)
Definition: bufmgr.h:396
PageData * Page
Definition: bufpage.h:82
BulkWriteState * smgr_bulk_start_rel(Relation rel, ForkNumber forknum)
Definition: bulk_write.c:87
void smgr_bulk_write(BulkWriteState *bulkstate, BlockNumber blocknum, BulkWriteBuffer buf, bool page_std)
Definition: bulk_write.c:323
BulkWriteBuffer smgr_bulk_get_buf(BulkWriteState *bulkstate)
Definition: bulk_write.c:347
void smgr_bulk_finish(BulkWriteState *bulkstate)
Definition: bulk_write.c:130
#define Assert(condition)
Definition: c.h:815
int64_t int64
Definition: c.h:485
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
IndexUniqueCheck
Definition: genam.h:118
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:383
void * palloc0(Size size)
Definition: mcxt.c:1347
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:454
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160
#define START_CRIT_SECTION()
Definition: miscadmin.h:149
#define END_CRIT_SECTION()
Definition: miscadmin.h:151
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
static char * buf
Definition: pg_test_fsync.c:72
uintptr_t Datum
Definition: postgres.h:69
#define RelationGetRelationName(relation)
Definition: rel.h:540
#define RelationNeedsWAL(relation)
Definition: rel.h:629
@ MAIN_FORKNUM
Definition: relpath.h:58
@ INIT_FORKNUM
Definition: relpath.h:61
bool spgdoinsert(Relation index, SpGistState *state, ItemPointer heapPtr, Datum *datums, bool *isnulls)
Definition: spgdoinsert.c:1914
IndexBuildResult * spgbuild(Relation heap, Relation index, IndexInfo *indexInfo)
Definition: spginsert.c:73
static void spgistBuildCallback(Relation index, ItemPointer tid, Datum *values, bool *isnull, bool tupleIsAlive, void *state)
Definition: spginsert.c:41
bool spginsert(Relation index, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, IndexUniqueCheck checkUnique, bool indexUnchanged, IndexInfo *indexInfo)
Definition: spginsert.c:183
void spgbuildempty(Relation index)
Definition: spginsert.c:154
#define SPGIST_NULL_BLKNO
#define SPGIST_METAPAGE_BLKNO
#define SPGIST_NULLS
#define SPGIST_LEAF
#define SPGIST_ROOT_BLKNO
void initSpGistState(SpGistState *state, Relation index)
Definition: spgutils.c:345
void SpGistUpdateMetaPage(Relation index)
Definition: spgutils.c:447
Buffer SpGistNewBuffer(Relation index)
Definition: spgutils.c:391
void SpGistInitBuffer(Buffer b, uint16 f)
Definition: spgutils.c:719
void SpGistInitPage(Page page, uint16 f)
Definition: spgutils.c:705
void SpGistInitMetapage(Page page)
Definition: spgutils.c:729
double heap_tuples
Definition: genam.h:34
double index_tuples
Definition: genam.h:35
MemoryContext tmpCtx
Definition: spginsert.c:35
SpGistState spgstate
Definition: spginsert.c:33
Definition: type.h:96
Definition: regguts.h:323
static double table_index_build_scan(Relation table_rel, Relation index_rel, struct IndexInfo *index_info, bool allow_sync, bool progress, IndexBuildCallback callback, void *callback_state, TableScanDesc scan)
Definition: tableam.h:1781
void log_newpage_range(Relation rel, ForkNumber forknum, BlockNumber startblk, BlockNumber endblk, bool page_std)
Definition: xloginsert.c:1270