Update obsolete nbtree array preprocessing comments.
[pgsql.git] / src / backend / access / spgist / spginsert.c
blob1bec19c2b88f7fe1879f05cc4c58baca215ef4b2
1 /*-------------------------------------------------------------------------
3 * spginsert.c
4 * Externally visible index creation/insertion routines
6 * All the actual insertion logic is in spgdoinsert.c.
8 * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
9 * Portions Copyright (c) 1994, Regents of the University of California
11 * IDENTIFICATION
12 * src/backend/access/spgist/spginsert.c
14 *-------------------------------------------------------------------------
17 #include "postgres.h"
19 #include "access/genam.h"
20 #include "access/spgist_private.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"
31 typedef struct
33 SpGistState spgstate; /* SPGiST's working state */
34 int64 indtuples; /* total number of tuples indexed */
35 MemoryContext tmpCtx; /* per-tuple temporary context */
36 } SpGistBuildState;
39 /* Callback to process one heap tuple during table_index_build_scan */
40 static void
41 spgistBuildCallback(Relation index, ItemPointer tid, Datum *values,
42 bool *isnull, bool tupleIsAlive, void *state)
44 SpGistBuildState *buildstate = (SpGistBuildState *) state;
45 MemoryContext oldCtx;
47 /* Work in temp context, and reset it after each tuple */
48 oldCtx = MemoryContextSwitchTo(buildstate->tmpCtx);
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.
56 while (!spgdoinsert(index, &buildstate->spgstate, tid,
57 values, isnull))
59 MemoryContextReset(buildstate->tmpCtx);
62 /* Update total tuple count */
63 buildstate->indtuples += 1;
65 MemoryContextSwitchTo(oldCtx);
66 MemoryContextReset(buildstate->tmpCtx);
70 * Build an SP-GiST index.
72 IndexBuildResult *
73 spgbuild(Relation heap, Relation index, IndexInfo *indexInfo)
75 IndexBuildResult *result;
76 double reltuples;
77 SpGistBuildState buildstate;
78 Buffer metabuffer,
79 rootbuffer,
80 nullbuffer;
82 if (RelationGetNumberOfBlocks(index) != 0)
83 elog(ERROR, "index \"%s\" already contains data",
84 RelationGetRelationName(index));
87 * Initialize the meta page and root pages
89 metabuffer = SpGistNewBuffer(index);
90 rootbuffer = SpGistNewBuffer(index);
91 nullbuffer = SpGistNewBuffer(index);
93 Assert(BufferGetBlockNumber(metabuffer) == SPGIST_METAPAGE_BLKNO);
94 Assert(BufferGetBlockNumber(rootbuffer) == SPGIST_ROOT_BLKNO);
95 Assert(BufferGetBlockNumber(nullbuffer) == SPGIST_NULL_BLKNO);
97 START_CRIT_SECTION();
99 SpGistInitMetapage(BufferGetPage(metabuffer));
100 MarkBufferDirty(metabuffer);
101 SpGistInitBuffer(rootbuffer, SPGIST_LEAF);
102 MarkBufferDirty(rootbuffer);
103 SpGistInitBuffer(nullbuffer, SPGIST_LEAF | SPGIST_NULLS);
104 MarkBufferDirty(nullbuffer);
107 END_CRIT_SECTION();
109 UnlockReleaseBuffer(metabuffer);
110 UnlockReleaseBuffer(rootbuffer);
111 UnlockReleaseBuffer(nullbuffer);
114 * Now insert all the heap data into the index
116 initSpGistState(&buildstate.spgstate, index);
117 buildstate.spgstate.isBuild = true;
118 buildstate.indtuples = 0;
120 buildstate.tmpCtx = AllocSetContextCreate(CurrentMemoryContext,
121 "SP-GiST build temporary context",
122 ALLOCSET_DEFAULT_SIZES);
124 reltuples = table_index_build_scan(heap, index, indexInfo, true, true,
125 spgistBuildCallback, (void *) &buildstate,
126 NULL);
128 MemoryContextDelete(buildstate.tmpCtx);
130 SpGistUpdateMetaPage(index);
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.
136 if (RelationNeedsWAL(index))
138 log_newpage_range(index, MAIN_FORKNUM,
139 0, RelationGetNumberOfBlocks(index),
140 true);
143 result = (IndexBuildResult *) palloc0(sizeof(IndexBuildResult));
144 result->heap_tuples = reltuples;
145 result->index_tuples = buildstate.indtuples;
147 return result;
151 * Build an empty SPGiST index in the initialization fork
153 void
154 spgbuildempty(Relation index)
156 BulkWriteState *bulkstate;
157 BulkWriteBuffer buf;
159 bulkstate = smgr_bulk_start_rel(index, INIT_FORKNUM);
161 /* Construct metapage. */
162 buf = smgr_bulk_get_buf(bulkstate);
163 SpGistInitMetapage((Page) buf);
164 smgr_bulk_write(bulkstate, SPGIST_METAPAGE_BLKNO, buf, true);
166 /* Likewise for the root page. */
167 buf = smgr_bulk_get_buf(bulkstate);
168 SpGistInitPage((Page) buf, SPGIST_LEAF);
169 smgr_bulk_write(bulkstate, SPGIST_ROOT_BLKNO, buf, true);
171 /* Likewise for the null-tuples root page. */
172 buf = smgr_bulk_get_buf(bulkstate);
173 SpGistInitPage((Page) buf, SPGIST_LEAF | SPGIST_NULLS);
174 smgr_bulk_write(bulkstate, SPGIST_NULL_BLKNO, buf, true);
176 smgr_bulk_finish(bulkstate);
180 * Insert one new tuple into an SPGiST index.
182 bool
183 spginsert(Relation index, Datum *values, bool *isnull,
184 ItemPointer ht_ctid, Relation heapRel,
185 IndexUniqueCheck checkUnique,
186 bool indexUnchanged,
187 IndexInfo *indexInfo)
189 SpGistState spgstate;
190 MemoryContext oldCtx;
191 MemoryContext insertCtx;
193 insertCtx = AllocSetContextCreate(CurrentMemoryContext,
194 "SP-GiST insert temporary context",
195 ALLOCSET_DEFAULT_SIZES);
196 oldCtx = MemoryContextSwitchTo(insertCtx);
198 initSpGistState(&spgstate, index);
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.
206 while (!spgdoinsert(index, &spgstate, ht_ctid, values, isnull))
208 MemoryContextReset(insertCtx);
209 initSpGistState(&spgstate, index);
212 SpGistUpdateMetaPage(index);
214 MemoryContextSwitchTo(oldCtx);
215 MemoryContextDelete(insertCtx);
217 /* return false since we've not done any unique check */
218 return false;