YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/postgres/src/backend/access/spgist/spginsert.c
Line
Count
Source (jump to first uncovered line)
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-2018, 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
  int64   indtuples;    /* total number of tuples indexed */
36
  MemoryContext tmpCtx;   /* per-tuple temporary context */
37
} SpGistBuildState;
38
39
40
/* Callback to process one heap tuple during IndexBuildHeapScan */
41
static void
42
spgistBuildCallback(Relation index, HeapTuple htup, Datum *values,
43
          bool *isnull, bool tupleIsAlive, void *state)
44
0
{
45
0
  SpGistBuildState *buildstate = (SpGistBuildState *) state;
46
0
  MemoryContext oldCtx;
47
48
  /* Work in temp context, and reset it after each tuple */
49
0
  oldCtx = MemoryContextSwitchTo(buildstate->tmpCtx);
50
51
  /*
52
   * Even though no concurrent insertions can be happening, we still might
53
   * get a buffer-locking failure due to bgwriter or checkpointer taking a
54
   * lock on some buffer.  So we need to be willing to retry.  We can flush
55
   * any temp data when retrying.
56
   */
57
0
  while (!spgdoinsert(index, &buildstate->spgstate, &htup->t_self,
58
0
            *values, *isnull))
59
0
  {
60
0
    MemoryContextReset(buildstate->tmpCtx);
61
0
  }
62
63
  /* Update total tuple count */
64
0
  buildstate->indtuples += 1;
65
66
0
  MemoryContextSwitchTo(oldCtx);
67
0
  MemoryContextReset(buildstate->tmpCtx);
68
0
}
69
70
/*
71
 * Build an SP-GiST index.
72
 */
73
IndexBuildResult *
74
spgbuild(Relation heap, Relation index, IndexInfo *indexInfo)
75
0
{
76
0
  IndexBuildResult *result;
77
0
  double    reltuples;
78
0
  SpGistBuildState buildstate;
79
0
  Buffer    metabuffer,
80
0
        rootbuffer,
81
0
        nullbuffer;
82
83
0
  if (RelationGetNumberOfBlocks(index) != 0)
84
0
    elog(ERROR, "index \"%s\" already contains data",
85
0
       RelationGetRelationName(index));
86
87
  /*
88
   * Initialize the meta page and root pages
89
   */
90
0
  metabuffer = SpGistNewBuffer(index);
91
0
  rootbuffer = SpGistNewBuffer(index);
92
0
  nullbuffer = SpGistNewBuffer(index);
93
94
0
  Assert(BufferGetBlockNumber(metabuffer) == SPGIST_METAPAGE_BLKNO);
95
0
  Assert(BufferGetBlockNumber(rootbuffer) == SPGIST_ROOT_BLKNO);
96
0
  Assert(BufferGetBlockNumber(nullbuffer) == SPGIST_NULL_BLKNO);
97
98
0
  START_CRIT_SECTION();
99
100
0
  SpGistInitMetapage(BufferGetPage(metabuffer));
101
0
  MarkBufferDirty(metabuffer);
102
0
  SpGistInitBuffer(rootbuffer, SPGIST_LEAF);
103
0
  MarkBufferDirty(rootbuffer);
104
0
  SpGistInitBuffer(nullbuffer, SPGIST_LEAF | SPGIST_NULLS);
105
0
  MarkBufferDirty(nullbuffer);
106
107
0
  if (RelationNeedsWAL(index))
108
0
  {
109
0
    XLogRecPtr  recptr;
110
111
0
    XLogBeginInsert();
112
113
    /*
114
     * Replay will re-initialize the pages, so don't take full pages
115
     * images.  No other data to log.
116
     */
117
0
    XLogRegisterBuffer(0, metabuffer, REGBUF_WILL_INIT | REGBUF_STANDARD);
118
0
    XLogRegisterBuffer(1, rootbuffer, REGBUF_WILL_INIT | REGBUF_STANDARD);
119
0
    XLogRegisterBuffer(2, nullbuffer, REGBUF_WILL_INIT | REGBUF_STANDARD);
120
121
0
    recptr = XLogInsert(RM_SPGIST_ID, XLOG_SPGIST_CREATE_INDEX);
122
123
0
    PageSetLSN(BufferGetPage(metabuffer), recptr);
124
0
    PageSetLSN(BufferGetPage(rootbuffer), recptr);
125
0
    PageSetLSN(BufferGetPage(nullbuffer), recptr);
126
0
  }
127
128
0
  END_CRIT_SECTION();
129
130
0
  UnlockReleaseBuffer(metabuffer);
131
0
  UnlockReleaseBuffer(rootbuffer);
132
0
  UnlockReleaseBuffer(nullbuffer);
133
134
  /*
135
   * Now insert all the heap data into the index
136
   */
137
0
  initSpGistState(&buildstate.spgstate, index);
138
0
  buildstate.spgstate.isBuild = true;
139
0
  buildstate.indtuples = 0;
140
141
0
  buildstate.tmpCtx = AllocSetContextCreate(GetCurrentMemoryContext(),
142
0
                        "SP-GiST build temporary context",
143
0
                        ALLOCSET_DEFAULT_SIZES);
144
145
0
  reltuples = IndexBuildHeapScan(heap, index, indexInfo, true,
146
0
                   spgistBuildCallback, (void *) &buildstate,
147
0
                   NULL);
148
149
0
  MemoryContextDelete(buildstate.tmpCtx);
150
151
0
  SpGistUpdateMetaPage(index);
152
153
0
  result = (IndexBuildResult *) palloc0(sizeof(IndexBuildResult));
154
0
  result->heap_tuples = reltuples;
155
0
  result->index_tuples = buildstate.indtuples;
156
157
0
  return result;
158
0
}
159
160
/*
161
 * Build an empty SPGiST index in the initialization fork
162
 */
163
void
164
spgbuildempty(Relation index)
165
0
{
166
0
  Page    page;
167
168
  /* Construct metapage. */
169
0
  page = (Page) palloc(BLCKSZ);
170
0
  SpGistInitMetapage(page);
171
172
  /*
173
   * Write the page and log it unconditionally.  This is important
174
   * particularly for indexes created on tablespaces and databases whose
175
   * creation happened after the last redo pointer as recovery removes any
176
   * of their existing content when the corresponding create records are
177
   * replayed.
178
   */
179
0
  PageSetChecksumInplace(page, SPGIST_METAPAGE_BLKNO);
180
0
  smgrwrite(index->rd_smgr, INIT_FORKNUM, SPGIST_METAPAGE_BLKNO,
181
0
        (char *) page, true);
182
0
  log_newpage(&index->rd_smgr->smgr_rnode.node, INIT_FORKNUM,
183
0
        SPGIST_METAPAGE_BLKNO, page, true);
184
185
  /* Likewise for the root page. */
186
0
  SpGistInitPage(page, SPGIST_LEAF);
187
188
0
  PageSetChecksumInplace(page, SPGIST_ROOT_BLKNO);
189
0
  smgrwrite(index->rd_smgr, INIT_FORKNUM, SPGIST_ROOT_BLKNO,
190
0
        (char *) page, true);
191
0
  log_newpage(&index->rd_smgr->smgr_rnode.node, INIT_FORKNUM,
192
0
        SPGIST_ROOT_BLKNO, page, true);
193
194
  /* Likewise for the null-tuples root page. */
195
0
  SpGistInitPage(page, SPGIST_LEAF | SPGIST_NULLS);
196
197
0
  PageSetChecksumInplace(page, SPGIST_NULL_BLKNO);
198
0
  smgrwrite(index->rd_smgr, INIT_FORKNUM, SPGIST_NULL_BLKNO,
199
0
        (char *) page, true);
200
0
  log_newpage(&index->rd_smgr->smgr_rnode.node, INIT_FORKNUM,
201
0
        SPGIST_NULL_BLKNO, page, true);
202
203
  /*
204
   * An immediate sync is required even if we xlog'd the pages, because the
205
   * writes did not go through shared buffers and therefore a concurrent
206
   * checkpoint may have moved the redo pointer past our xlog record.
207
   */
208
0
  smgrimmedsync(index->rd_smgr, INIT_FORKNUM);
209
0
}
210
211
/*
212
 * Insert one new tuple into an SPGiST index.
213
 */
214
bool
215
spginsert(Relation index, Datum *values, bool *isnull,
216
      ItemPointer ht_ctid, Relation heapRel,
217
      IndexUniqueCheck checkUnique,
218
      IndexInfo *indexInfo)
219
0
{
220
0
  SpGistState spgstate;
221
0
  MemoryContext oldCtx;
222
0
  MemoryContext insertCtx;
223
224
0
  insertCtx = AllocSetContextCreate(GetCurrentMemoryContext(),
225
0
                    "SP-GiST insert temporary context",
226
0
                    ALLOCSET_DEFAULT_SIZES);
227
0
  oldCtx = MemoryContextSwitchTo(insertCtx);
228
229
0
  initSpGistState(&spgstate, index);
230
231
  /*
232
   * We might have to repeat spgdoinsert() multiple times, if conflicts
233
   * occur with concurrent insertions.  If so, reset the insertCtx each time
234
   * to avoid cumulative memory consumption.  That means we also have to
235
   * redo initSpGistState(), but it's cheap enough not to matter.
236
   */
237
0
  while (!spgdoinsert(index, &spgstate, ht_ctid, *values, *isnull))
238
0
  {
239
0
    MemoryContextReset(insertCtx);
240
0
    initSpGistState(&spgstate, index);
241
0
  }
242
243
0
  SpGistUpdateMetaPage(index);
244
245
0
  MemoryContextSwitchTo(oldCtx);
246
0
  MemoryContextDelete(insertCtx);
247
248
  /* return false since we've not done any unique check */
249
0
  return false;
250
0
}