Age Owner Branch data TLA Line data Source code
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-2024, 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/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 : :
31 : : typedef struct
32 : : {
33 : : SpGistState spgstate; /* SPGiST's working state */
34 : : int64 indtuples; /* total number of tuples indexed */
35 : : MemoryContext tmpCtx; /* per-tuple temporary context */
36 : : } SpGistBuildState;
37 : :
38 : :
39 : : /* Callback to process one heap tuple during table_index_build_scan */
40 : : static void
1619 andres@anarazel.de 41 :CBC 281387 : spgistBuildCallback(Relation index, ItemPointer tid, Datum *values,
42 : : bool *isnull, bool tupleIsAlive, void *state)
43 : : {
4502 tgl@sss.pgh.pa.us 44 : 281387 : SpGistBuildState *buildstate = (SpGistBuildState *) state;
45 : : MemoryContext oldCtx;
46 : :
47 : : /* Work in temp context, and reset it after each tuple */
4417 48 : 281387 : 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 : : */
1619 andres@anarazel.de 56 [ - + ]: 281387 : while (!spgdoinsert(index, &buildstate->spgstate, tid,
57 : : values, isnull))
58 : : {
3816 tgl@sss.pgh.pa.us 59 :UBC 0 : MemoryContextReset(buildstate->tmpCtx);
60 : : }
61 : :
62 : : /* Update total tuple count */
2215 tgl@sss.pgh.pa.us 63 :CBC 281387 : buildstate->indtuples += 1;
64 : :
4417 65 : 281387 : MemoryContextSwitchTo(oldCtx);
66 : 281387 : MemoryContextReset(buildstate->tmpCtx);
4502 67 : 281387 : }
68 : :
69 : : /*
70 : : * Build an SP-GiST index.
71 : : */
72 : : IndexBuildResult *
3010 73 : 104 : spgbuild(Relation heap, Relation index, IndexInfo *indexInfo)
74 : : {
75 : : IndexBuildResult *result;
76 : : double reltuples;
77 : : SpGistBuildState buildstate;
78 : : Buffer metabuffer,
79 : : rootbuffer,
80 : : nullbuffer;
81 : :
4502 82 [ - + ]: 104 : if (RelationGetNumberOfBlocks(index) != 0)
4502 tgl@sss.pgh.pa.us 83 [ # # ]:UBC 0 : elog(ERROR, "index \"%s\" already contains data",
84 : : RelationGetRelationName(index));
85 : :
86 : : /*
87 : : * Initialize the meta page and root pages
88 : : */
4502 tgl@sss.pgh.pa.us 89 :CBC 104 : metabuffer = SpGistNewBuffer(index);
90 : 104 : rootbuffer = SpGistNewBuffer(index);
4417 91 : 104 : nullbuffer = SpGistNewBuffer(index);
92 : :
4502 93 [ - + ]: 104 : Assert(BufferGetBlockNumber(metabuffer) == SPGIST_METAPAGE_BLKNO);
4417 94 [ - + ]: 104 : Assert(BufferGetBlockNumber(rootbuffer) == SPGIST_ROOT_BLKNO);
95 [ - + ]: 104 : Assert(BufferGetBlockNumber(nullbuffer) == SPGIST_NULL_BLKNO);
96 : :
4502 97 : 104 : START_CRIT_SECTION();
98 : :
2916 kgrittn@postgresql.o 99 : 104 : SpGistInitMetapage(BufferGetPage(metabuffer));
4502 tgl@sss.pgh.pa.us 100 : 104 : MarkBufferDirty(metabuffer);
101 : 104 : SpGistInitBuffer(rootbuffer, SPGIST_LEAF);
102 : 104 : MarkBufferDirty(rootbuffer);
4417 103 : 104 : SpGistInitBuffer(nullbuffer, SPGIST_LEAF | SPGIST_NULLS);
104 : 104 : MarkBufferDirty(nullbuffer);
105 : :
106 : :
4502 107 [ - + ]: 104 : END_CRIT_SECTION();
108 : :
109 : 104 : UnlockReleaseBuffer(metabuffer);
110 : 104 : UnlockReleaseBuffer(rootbuffer);
4417 111 : 104 : UnlockReleaseBuffer(nullbuffer);
112 : :
113 : : /*
114 : : * Now insert all the heap data into the index
115 : : */
4502 116 : 104 : initSpGistState(&buildstate.spgstate, index);
117 : 104 : buildstate.spgstate.isBuild = true;
2215 118 : 104 : buildstate.indtuples = 0;
119 : :
4502 120 : 104 : buildstate.tmpCtx = AllocSetContextCreate(CurrentMemoryContext,
121 : : "SP-GiST build temporary context",
122 : : ALLOCSET_DEFAULT_SIZES);
123 : :
1839 alvherre@alvh.no-ip. 124 : 104 : reltuples = table_index_build_scan(heap, index, indexInfo, true, true,
125 : : spgistBuildCallback, (void *) &buildstate,
126 : : NULL);
127 : :
4502 tgl@sss.pgh.pa.us 128 : 104 : MemoryContextDelete(buildstate.tmpCtx);
129 : :
130 : 104 : SpGistUpdateMetaPage(index);
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 : : */
1838 heikki.linnakangas@i 136 [ + + + + : 104 : if (RelationNeedsWAL(index))
+ + - + ]
137 : : {
138 : 37 : log_newpage_range(index, MAIN_FORKNUM,
139 : : 0, RelationGetNumberOfBlocks(index),
140 : : true);
141 : : }
142 : :
4502 tgl@sss.pgh.pa.us 143 : 104 : result = (IndexBuildResult *) palloc0(sizeof(IndexBuildResult));
2215 144 : 104 : result->heap_tuples = reltuples;
145 : 104 : result->index_tuples = buildstate.indtuples;
146 : :
3010 147 : 104 : return result;
148 : : }
149 : :
150 : : /*
151 : : * Build an empty SPGiST index in the initialization fork
152 : : */
153 : : void
154 : 4 : spgbuildempty(Relation index)
155 : : {
156 : : BulkWriteState *bulkstate;
157 : : BulkWriteBuffer buf;
158 : :
51 heikki.linnakangas@i 159 :GNC 4 : bulkstate = smgr_bulk_start_rel(index, INIT_FORKNUM);
160 : :
161 : : /* Construct metapage. */
162 : 4 : buf = smgr_bulk_get_buf(bulkstate);
163 : 4 : SpGistInitMetapage((Page) buf);
164 : 4 : smgr_bulk_write(bulkstate, SPGIST_METAPAGE_BLKNO, buf, true);
165 : :
166 : : /* Likewise for the root page. */
167 : 4 : buf = smgr_bulk_get_buf(bulkstate);
168 : 4 : SpGistInitPage((Page) buf, SPGIST_LEAF);
169 : 4 : smgr_bulk_write(bulkstate, SPGIST_ROOT_BLKNO, buf, true);
170 : :
171 : : /* Likewise for the null-tuples root page. */
172 : 4 : buf = smgr_bulk_get_buf(bulkstate);
173 : 4 : SpGistInitPage((Page) buf, SPGIST_LEAF | SPGIST_NULLS);
174 : 4 : smgr_bulk_write(bulkstate, SPGIST_NULL_BLKNO, buf, true);
175 : :
176 : 4 : smgr_bulk_finish(bulkstate);
4502 tgl@sss.pgh.pa.us 177 :CBC 4 : }
178 : :
179 : : /*
180 : : * Insert one new tuple into an SPGiST index.
181 : : */
182 : : bool
3010 183 : 121294 : spginsert(Relation index, Datum *values, bool *isnull,
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 : :
4502 193 : 121294 : insertCtx = AllocSetContextCreate(CurrentMemoryContext,
194 : : "SP-GiST insert temporary context",
195 : : ALLOCSET_DEFAULT_SIZES);
196 : 121294 : oldCtx = MemoryContextSwitchTo(insertCtx);
197 : :
198 : 121294 : 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 : : */
1105 206 [ - + ]: 121294 : while (!spgdoinsert(index, &spgstate, ht_ctid, values, isnull))
207 : : {
3957 tgl@sss.pgh.pa.us 208 :UBC 0 : MemoryContextReset(insertCtx);
209 : 0 : initSpGistState(&spgstate, index);
210 : : }
211 : :
4502 tgl@sss.pgh.pa.us 212 :CBC 121292 : SpGistUpdateMetaPage(index);
213 : :
214 : 121292 : MemoryContextSwitchTo(oldCtx);
215 : 121292 : MemoryContextDelete(insertCtx);
216 : :
217 : : /* return false since we've not done any unique check */
3010 218 : 121292 : return false;
219 : : }
|