Header And Logo

PostgreSQL
| The world's most advanced open source database.

spginsert.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * spginsert.c
00004  *    Externally visible index creation/insertion routines
00005  *
00006  * All the actual insertion logic is in spgdoinsert.c.
00007  *
00008  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00009  * Portions Copyright (c) 1994, Regents of the University of California
00010  *
00011  * IDENTIFICATION
00012  *          src/backend/access/spgist/spginsert.c
00013  *
00014  *-------------------------------------------------------------------------
00015  */
00016 
00017 #include "postgres.h"
00018 
00019 #include "access/genam.h"
00020 #include "access/heapam_xlog.h"
00021 #include "access/spgist_private.h"
00022 #include "catalog/index.h"
00023 #include "miscadmin.h"
00024 #include "storage/bufmgr.h"
00025 #include "storage/smgr.h"
00026 #include "utils/memutils.h"
00027 #include "utils/rel.h"
00028 
00029 
00030 typedef struct
00031 {
00032     SpGistState spgstate;       /* SPGiST's working state */
00033     MemoryContext tmpCtx;       /* per-tuple temporary context */
00034 } SpGistBuildState;
00035 
00036 
00037 /* Callback to process one heap tuple during IndexBuildHeapScan */
00038 static void
00039 spgistBuildCallback(Relation index, HeapTuple htup, Datum *values,
00040                     bool *isnull, bool tupleIsAlive, void *state)
00041 {
00042     SpGistBuildState *buildstate = (SpGistBuildState *) state;
00043     MemoryContext oldCtx;
00044 
00045     /* Work in temp context, and reset it after each tuple */
00046     oldCtx = MemoryContextSwitchTo(buildstate->tmpCtx);
00047 
00048     spgdoinsert(index, &buildstate->spgstate, &htup->t_self, *values, *isnull);
00049 
00050     MemoryContextSwitchTo(oldCtx);
00051     MemoryContextReset(buildstate->tmpCtx);
00052 }
00053 
00054 /*
00055  * Build an SP-GiST index.
00056  */
00057 Datum
00058 spgbuild(PG_FUNCTION_ARGS)
00059 {
00060     Relation    heap = (Relation) PG_GETARG_POINTER(0);
00061     Relation    index = (Relation) PG_GETARG_POINTER(1);
00062     IndexInfo  *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2);
00063     IndexBuildResult *result;
00064     double      reltuples;
00065     SpGistBuildState buildstate;
00066     Buffer      metabuffer,
00067                 rootbuffer,
00068                 nullbuffer;
00069 
00070     if (RelationGetNumberOfBlocks(index) != 0)
00071         elog(ERROR, "index \"%s\" already contains data",
00072              RelationGetRelationName(index));
00073 
00074     /*
00075      * Initialize the meta page and root pages
00076      */
00077     metabuffer = SpGistNewBuffer(index);
00078     rootbuffer = SpGistNewBuffer(index);
00079     nullbuffer = SpGistNewBuffer(index);
00080 
00081     Assert(BufferGetBlockNumber(metabuffer) == SPGIST_METAPAGE_BLKNO);
00082     Assert(BufferGetBlockNumber(rootbuffer) == SPGIST_ROOT_BLKNO);
00083     Assert(BufferGetBlockNumber(nullbuffer) == SPGIST_NULL_BLKNO);
00084 
00085     START_CRIT_SECTION();
00086 
00087     SpGistInitMetapage(BufferGetPage(metabuffer));
00088     MarkBufferDirty(metabuffer);
00089     SpGistInitBuffer(rootbuffer, SPGIST_LEAF);
00090     MarkBufferDirty(rootbuffer);
00091     SpGistInitBuffer(nullbuffer, SPGIST_LEAF | SPGIST_NULLS);
00092     MarkBufferDirty(nullbuffer);
00093 
00094     if (RelationNeedsWAL(index))
00095     {
00096         XLogRecPtr  recptr;
00097         XLogRecData rdata;
00098 
00099         /* WAL data is just the relfilenode */
00100         rdata.data = (char *) &(index->rd_node);
00101         rdata.len = sizeof(RelFileNode);
00102         rdata.buffer = InvalidBuffer;
00103         rdata.next = NULL;
00104 
00105         recptr = XLogInsert(RM_SPGIST_ID, XLOG_SPGIST_CREATE_INDEX, &rdata);
00106 
00107         PageSetLSN(BufferGetPage(metabuffer), recptr);
00108         PageSetLSN(BufferGetPage(rootbuffer), recptr);
00109         PageSetLSN(BufferGetPage(nullbuffer), recptr);
00110     }
00111 
00112     END_CRIT_SECTION();
00113 
00114     UnlockReleaseBuffer(metabuffer);
00115     UnlockReleaseBuffer(rootbuffer);
00116     UnlockReleaseBuffer(nullbuffer);
00117 
00118     /*
00119      * Now insert all the heap data into the index
00120      */
00121     initSpGistState(&buildstate.spgstate, index);
00122     buildstate.spgstate.isBuild = true;
00123 
00124     buildstate.tmpCtx = AllocSetContextCreate(CurrentMemoryContext,
00125                                            "SP-GiST build temporary context",
00126                                               ALLOCSET_DEFAULT_MINSIZE,
00127                                               ALLOCSET_DEFAULT_INITSIZE,
00128                                               ALLOCSET_DEFAULT_MAXSIZE);
00129 
00130     reltuples = IndexBuildHeapScan(heap, index, indexInfo, true,
00131                                    spgistBuildCallback, (void *) &buildstate);
00132 
00133     MemoryContextDelete(buildstate.tmpCtx);
00134 
00135     SpGistUpdateMetaPage(index);
00136 
00137     result = (IndexBuildResult *) palloc0(sizeof(IndexBuildResult));
00138     result->heap_tuples = result->index_tuples = reltuples;
00139 
00140     PG_RETURN_POINTER(result);
00141 }
00142 
00143 /*
00144  * Build an empty SPGiST index in the initialization fork
00145  */
00146 Datum
00147 spgbuildempty(PG_FUNCTION_ARGS)
00148 {
00149     Relation    index = (Relation) PG_GETARG_POINTER(0);
00150     Page        page;
00151 
00152     /* Construct metapage. */
00153     page = (Page) palloc(BLCKSZ);
00154     SpGistInitMetapage(page);
00155 
00156     /* Write the page.  If archiving/streaming, XLOG it. */
00157     PageSetChecksumInplace(page, SPGIST_METAPAGE_BLKNO);
00158     smgrwrite(index->rd_smgr, INIT_FORKNUM, SPGIST_METAPAGE_BLKNO,
00159               (char *) page, true);
00160     if (XLogIsNeeded())
00161         log_newpage(&index->rd_smgr->smgr_rnode.node, INIT_FORKNUM,
00162                     SPGIST_METAPAGE_BLKNO, page);
00163 
00164     /* Likewise for the root page. */
00165     SpGistInitPage(page, SPGIST_LEAF);
00166 
00167     PageSetChecksumInplace(page, SPGIST_ROOT_BLKNO);
00168     smgrwrite(index->rd_smgr, INIT_FORKNUM, SPGIST_ROOT_BLKNO,
00169               (char *) page, true);
00170     if (XLogIsNeeded())
00171         log_newpage(&index->rd_smgr->smgr_rnode.node, INIT_FORKNUM,
00172                     SPGIST_ROOT_BLKNO, page);
00173 
00174     /* Likewise for the null-tuples root page. */
00175     SpGistInitPage(page, SPGIST_LEAF | SPGIST_NULLS);
00176 
00177     PageSetChecksumInplace(page, SPGIST_NULL_BLKNO);
00178     smgrwrite(index->rd_smgr, INIT_FORKNUM, SPGIST_NULL_BLKNO,
00179               (char *) page, true);
00180     if (XLogIsNeeded())
00181         log_newpage(&index->rd_smgr->smgr_rnode.node, INIT_FORKNUM,
00182                     SPGIST_NULL_BLKNO, page);
00183 
00184     /*
00185      * An immediate sync is required even if we xlog'd the pages, because the
00186      * writes did not go through shared buffers and therefore a concurrent
00187      * checkpoint may have moved the redo pointer past our xlog record.
00188      */
00189     smgrimmedsync(index->rd_smgr, INIT_FORKNUM);
00190 
00191     PG_RETURN_VOID();
00192 }
00193 
00194 /*
00195  * Insert one new tuple into an SPGiST index.
00196  */
00197 Datum
00198 spginsert(PG_FUNCTION_ARGS)
00199 {
00200     Relation    index = (Relation) PG_GETARG_POINTER(0);
00201     Datum      *values = (Datum *) PG_GETARG_POINTER(1);
00202     bool       *isnull = (bool *) PG_GETARG_POINTER(2);
00203     ItemPointer ht_ctid = (ItemPointer) PG_GETARG_POINTER(3);
00204 
00205 #ifdef NOT_USED
00206     Relation    heapRel = (Relation) PG_GETARG_POINTER(4);
00207     IndexUniqueCheck checkUnique = (IndexUniqueCheck) PG_GETARG_INT32(5);
00208 #endif
00209     SpGistState spgstate;
00210     MemoryContext oldCtx;
00211     MemoryContext insertCtx;
00212 
00213     insertCtx = AllocSetContextCreate(CurrentMemoryContext,
00214                                       "SP-GiST insert temporary context",
00215                                       ALLOCSET_DEFAULT_MINSIZE,
00216                                       ALLOCSET_DEFAULT_INITSIZE,
00217                                       ALLOCSET_DEFAULT_MAXSIZE);
00218     oldCtx = MemoryContextSwitchTo(insertCtx);
00219 
00220     initSpGistState(&spgstate, index);
00221 
00222     spgdoinsert(index, &spgstate, ht_ctid, *values, *isnull);
00223 
00224     SpGistUpdateMetaPage(index);
00225 
00226     MemoryContextSwitchTo(oldCtx);
00227     MemoryContextDelete(insertCtx);
00228 
00229     /* return false since we've not done any unique check */
00230     PG_RETURN_BOOL(false);
00231 }