LTP GCOV extension - code coverage report
Current view: directory - access/gin - gininsert.c
Test: unnamed
Date: 2008-07-03 Instrumented lines: 145
Code covered: 89.7 % Executed lines: 130
Legend: not executed executed

       1                 : /*-------------------------------------------------------------------------
       2                 :  *
       3                 :  * gininsert.c
       4                 :  *        insert routines for the postgres inverted index access method.
       5                 :  *
       6                 :  *
       7                 :  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
       8                 :  * Portions Copyright (c) 1994, Regents of the University of California
       9                 :  *
      10                 :  * IDENTIFICATION
      11                 :  *                      $PostgreSQL: pgsql/src/backend/access/gin/gininsert.c,v 1.10 2007/11/16 21:55:59 tgl Exp $
      12                 :  *-------------------------------------------------------------------------
      13                 :  */
      14                 : 
      15                 : #include "postgres.h"
      16                 : 
      17                 : #include "access/genam.h"
      18                 : #include "access/gin.h"
      19                 : #include "catalog/index.h"
      20                 : #include "miscadmin.h"
      21                 : #include "utils/memutils.h"
      22                 : 
      23                 : 
      24                 : typedef struct
      25                 : {
      26                 :         GinState        ginstate;
      27                 :         double          indtuples;
      28                 :         MemoryContext tmpCtx;
      29                 :         MemoryContext funcCtx;
      30                 :         BuildAccumulator accum;
      31                 : } GinBuildState;
      32                 : 
      33                 : /*
      34                 :  * Creates posting tree with one page. Function
      35                 :  * suppose that items[] fits to page
      36                 :  */
      37                 : static BlockNumber
      38                 : createPostingTree(Relation index, ItemPointerData *items, uint32 nitems)
      39              19 : {
      40                 :         BlockNumber blkno;
      41              19 :         Buffer          buffer = GinNewBuffer(index);
      42                 :         Page            page;
      43                 : 
      44              19 :         START_CRIT_SECTION();
      45                 : 
      46              19 :         GinInitBuffer(buffer, GIN_DATA | GIN_LEAF);
      47              19 :         page = BufferGetPage(buffer);
      48              19 :         blkno = BufferGetBlockNumber(buffer);
      49                 : 
      50              19 :         memcpy(GinDataPageGetData(page), items, sizeof(ItemPointerData) * nitems);
      51              19 :         GinPageGetOpaque(page)->maxoff = nitems;
      52                 : 
      53              19 :         MarkBufferDirty(buffer);
      54                 : 
      55              19 :         if (!index->rd_istemp)
      56                 :         {
      57                 :                 XLogRecPtr      recptr;
      58                 :                 XLogRecData rdata[2];
      59                 :                 ginxlogCreatePostingTree data;
      60                 : 
      61              19 :                 data.node = index->rd_node;
      62              19 :                 data.blkno = blkno;
      63              19 :                 data.nitem = nitems;
      64                 : 
      65              19 :                 rdata[0].buffer = InvalidBuffer;
      66              19 :                 rdata[0].data = (char *) &data;
      67              19 :                 rdata[0].len = sizeof(ginxlogCreatePostingTree);
      68              19 :                 rdata[0].next = &rdata[1];
      69                 : 
      70              19 :                 rdata[1].buffer = InvalidBuffer;
      71              19 :                 rdata[1].data = (char *) items;
      72              19 :                 rdata[1].len = sizeof(ItemPointerData) * nitems;
      73              19 :                 rdata[1].next = NULL;
      74                 : 
      75                 : 
      76                 : 
      77              19 :                 recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_CREATE_PTREE, rdata);
      78              19 :                 PageSetLSN(page, recptr);
      79              19 :                 PageSetTLI(page, ThisTimeLineID);
      80                 : 
      81                 :         }
      82                 : 
      83              19 :         UnlockReleaseBuffer(buffer);
      84                 : 
      85              19 :         END_CRIT_SECTION();
      86                 : 
      87              19 :         return blkno;
      88                 : }
      89                 : 
      90                 : 
      91                 : /*
      92                 :  * Adds array of item pointers to tuple's posting list or
      93                 :  * creates posting tree and tuple pointed to tree in a case
      94                 :  * of not enough space.  Max size of tuple is defined in
      95                 :  * GinFormTuple().
      96                 :  */
      97                 : static IndexTuple
      98                 : addItemPointersToTuple(Relation index, GinState *ginstate, GinBtreeStack *stack,
      99                 :                   IndexTuple old, ItemPointerData *items, uint32 nitem, bool isBuild)
     100            1312 : {
     101                 :         bool            isnull;
     102            1312 :         Datum           key = index_getattr(old, FirstOffsetNumber, ginstate->tupdesc, &isnull);
     103            1312 :         IndexTuple      res = GinFormTuple(ginstate, key, NULL, nitem + GinGetNPosting(old));
     104                 : 
     105            1312 :         if (res)
     106                 :         {
     107                 :                 /* good, small enough */
     108            1293 :                 MergeItemPointers(GinGetPosting(res),
     109                 :                                                   GinGetPosting(old), GinGetNPosting(old),
     110                 :                                                   items, nitem
     111                 :                         );
     112                 : 
     113            1293 :                 GinSetNPosting(res, nitem + GinGetNPosting(old));
     114                 :         }
     115                 :         else
     116                 :         {
     117                 :                 BlockNumber postingRoot;
     118                 :                 GinPostingTreeScan *gdi;
     119                 : 
     120                 :                 /* posting list becomes big, so we need to make posting's tree */
     121              19 :                 res = GinFormTuple(ginstate, key, NULL, 0);
     122              19 :                 postingRoot = createPostingTree(index, GinGetPosting(old), GinGetNPosting(old));
     123              19 :                 GinSetPostingTree(res, postingRoot);
     124                 : 
     125              19 :                 gdi = prepareScanPostingTree(index, postingRoot, FALSE);
     126              19 :                 gdi->btree.isBuild = isBuild;
     127                 : 
     128              19 :                 insertItemPointer(gdi, items, nitem);
     129                 : 
     130              19 :                 pfree(gdi);
     131                 :         }
     132                 : 
     133            1312 :         return res;
     134                 : }
     135                 : 
     136                 : /*
     137                 :  * Inserts only one entry to the index, but it can add more than 1 ItemPointer.
     138                 :  */
     139                 : static void
     140                 : ginEntryInsert(Relation index, GinState *ginstate, Datum value, ItemPointerData *items, uint32 nitem, bool isBuild)
     141            1436 : {
     142                 :         GinBtreeData btree;
     143                 :         GinBtreeStack *stack;
     144                 :         IndexTuple      itup;
     145                 :         Page            page;
     146                 : 
     147            1436 :         prepareEntryScan(&btree, index, value, ginstate);
     148                 : 
     149            1436 :         stack = ginFindLeafPage(&btree, NULL);
     150            1436 :         page = BufferGetPage(stack->buffer);
     151                 : 
     152            1436 :         if (btree.findItem(&btree, stack))
     153                 :         {
     154                 :                 /* found entry */
     155               2 :                 itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, stack->off));
     156                 : 
     157               2 :                 if (GinIsPostingTree(itup))
     158                 :                 {
     159                 :                         /* lock root of posting tree */
     160                 :                         GinPostingTreeScan *gdi;
     161               0 :                         BlockNumber rootPostingTree = GinGetPostingTree(itup);
     162                 : 
     163                 :                         /* release all stack */
     164               0 :                         LockBuffer(stack->buffer, GIN_UNLOCK);
     165               0 :                         freeGinBtreeStack(stack);
     166                 : 
     167                 :                         /* insert into posting tree */
     168               0 :                         gdi = prepareScanPostingTree(index, rootPostingTree, FALSE);
     169               0 :                         gdi->btree.isBuild = isBuild;
     170               0 :                         insertItemPointer(gdi, items, nitem);
     171                 : 
     172               0 :                         return;
     173                 :                 }
     174                 : 
     175               2 :                 itup = addItemPointersToTuple(index, ginstate, stack, itup, items, nitem, isBuild);
     176                 : 
     177               2 :                 btree.isDelete = TRUE;
     178                 :         }
     179                 :         else
     180                 :         {
     181                 :                 /* We suppose, that tuple can store at list one itempointer */
     182            1434 :                 itup = GinFormTuple(ginstate, value, items, 1);
     183            1434 :                 if (itup == NULL || IndexTupleSize(itup) >= GinMaxItemSize)
     184               0 :                         elog(ERROR, "huge tuple");
     185                 : 
     186            1434 :                 if (nitem > 1)
     187                 :                 {
     188            1310 :                         IndexTuple      previtup = itup;
     189                 : 
     190            1310 :                         itup = addItemPointersToTuple(index, ginstate, stack, previtup, items + 1, nitem - 1, isBuild);
     191            1310 :                         pfree(previtup);
     192                 :                 }
     193                 :         }
     194                 : 
     195            1436 :         btree.entry = itup;
     196            1436 :         ginInsertValue(&btree, stack);
     197            1436 :         pfree(itup);
     198                 : }
     199                 : 
     200                 : /*
     201                 :  * Saves indexed value in memory accumulator during index creation
     202                 :  * Function isn't used during normal insert
     203                 :  */
     204                 : static uint32
     205                 : ginHeapTupleBulkInsert(GinBuildState *buildstate, Datum value, ItemPointer heapptr)
     206             708 : {
     207                 :         Datum      *entries;
     208                 :         int32           nentries;
     209                 :         MemoryContext oldCtx;
     210                 : 
     211            1416 :         oldCtx = MemoryContextSwitchTo(buildstate->funcCtx);
     212             708 :         entries = extractEntriesSU(buildstate->accum.ginstate, value, &nentries);
     213                 :         MemoryContextSwitchTo(oldCtx);
     214                 : 
     215             708 :         if (nentries == 0)
     216                 :                 /* nothing to insert */
     217               8 :                 return 0;
     218                 : 
     219             700 :         ginInsertRecordBA(&buildstate->accum, heapptr, entries, nentries);
     220                 : 
     221             700 :         MemoryContextReset(buildstate->funcCtx);
     222                 : 
     223             700 :         return nentries;
     224                 : }
     225                 : 
     226                 : static void
     227                 : ginBuildCallback(Relation index, HeapTuple htup, Datum *values,
     228                 :                                  bool *isnull, bool tupleIsAlive, void *state)
     229             708 : {
     230             708 :         GinBuildState *buildstate = (GinBuildState *) state;
     231                 :         MemoryContext oldCtx;
     232                 : 
     233             708 :         if (*isnull)
     234               0 :                 return;
     235                 : 
     236             708 :         oldCtx = MemoryContextSwitchTo(buildstate->tmpCtx);
     237                 : 
     238             708 :         buildstate->indtuples += ginHeapTupleBulkInsert(buildstate, *values, &htup->t_self);
     239                 : 
     240                 :         /* If we've maxed out our available memory, dump everything to the index */
     241             708 :         if (buildstate->accum.allocatedMemory >= maintenance_work_mem * 1024L)
     242                 :         {
     243                 :                 ItemPointerData *list;
     244                 :                 Datum           entry;
     245                 :                 uint32          nlist;
     246                 : 
     247               0 :                 while ((list = ginGetEntry(&buildstate->accum, &entry, &nlist)) != NULL)
     248               0 :                         ginEntryInsert(index, &buildstate->ginstate, entry, list, nlist, TRUE);
     249                 : 
     250               0 :                 MemoryContextReset(buildstate->tmpCtx);
     251               0 :                 ginInitBA(&buildstate->accum);
     252                 :         }
     253                 : 
     254             708 :         MemoryContextSwitchTo(oldCtx);
     255                 : }
     256                 : 
     257                 : Datum
     258                 : ginbuild(PG_FUNCTION_ARGS)
     259               3 : {
     260               3 :         Relation        heap = (Relation) PG_GETARG_POINTER(0);
     261               3 :         Relation        index = (Relation) PG_GETARG_POINTER(1);
     262               3 :         IndexInfo  *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2);
     263                 :         IndexBuildResult *result;
     264                 :         double          reltuples;
     265                 :         GinBuildState buildstate;
     266                 :         Buffer          buffer;
     267                 :         ItemPointerData *list;
     268                 :         Datum           entry;
     269                 :         uint32          nlist;
     270                 :         MemoryContext oldCtx;
     271                 : 
     272               3 :         if (RelationGetNumberOfBlocks(index) != 0)
     273               0 :                 elog(ERROR, "index \"%s\" already contains data",
     274                 :                          RelationGetRelationName(index));
     275                 : 
     276               3 :         initGinState(&buildstate.ginstate, index);
     277                 : 
     278                 :         /* initialize the root page */
     279               3 :         buffer = GinNewBuffer(index);
     280               3 :         START_CRIT_SECTION();
     281               3 :         GinInitBuffer(buffer, GIN_LEAF);
     282               3 :         MarkBufferDirty(buffer);
     283                 : 
     284               3 :         if (!index->rd_istemp)
     285                 :         {
     286                 :                 XLogRecPtr      recptr;
     287                 :                 XLogRecData rdata;
     288                 :                 Page            page;
     289                 : 
     290               3 :                 rdata.buffer = InvalidBuffer;
     291               3 :                 rdata.data = (char *) &(index->rd_node);
     292               3 :                 rdata.len = sizeof(RelFileNode);
     293               3 :                 rdata.next = NULL;
     294                 : 
     295               3 :                 page = BufferGetPage(buffer);
     296                 : 
     297                 : 
     298               3 :                 recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_CREATE_INDEX, &rdata);
     299               3 :                 PageSetLSN(page, recptr);
     300               3 :                 PageSetTLI(page, ThisTimeLineID);
     301                 : 
     302                 :         }
     303                 : 
     304               3 :         UnlockReleaseBuffer(buffer);
     305               3 :         END_CRIT_SECTION();
     306                 : 
     307                 :         /* build the index */
     308               3 :         buildstate.indtuples = 0;
     309                 : 
     310                 :         /*
     311                 :          * create a temporary memory context that is reset once for each tuple
     312                 :          * inserted into the index
     313                 :          */
     314               3 :         buildstate.tmpCtx = AllocSetContextCreate(CurrentMemoryContext,
     315                 :                                                                                           "Gin build temporary context",
     316                 :                                                                                           ALLOCSET_DEFAULT_MINSIZE,
     317                 :                                                                                           ALLOCSET_DEFAULT_INITSIZE,
     318                 :                                                                                           ALLOCSET_DEFAULT_MAXSIZE);
     319                 : 
     320               3 :         buildstate.funcCtx = AllocSetContextCreate(buildstate.tmpCtx,
     321                 :                                          "Gin build temporary context for user-defined function",
     322                 :                                                                                            ALLOCSET_DEFAULT_MINSIZE,
     323                 :                                                                                            ALLOCSET_DEFAULT_INITSIZE,
     324                 :                                                                                            ALLOCSET_DEFAULT_MAXSIZE);
     325                 : 
     326               3 :         buildstate.accum.ginstate = &buildstate.ginstate;
     327               3 :         ginInitBA(&buildstate.accum);
     328                 : 
     329                 :         /* do the heap scan */
     330               3 :         reltuples = IndexBuildHeapScan(heap, index, indexInfo,
     331                 :                                                                    ginBuildCallback, (void *) &buildstate);
     332                 : 
     333               3 :         oldCtx = MemoryContextSwitchTo(buildstate.tmpCtx);
     334            1436 :         while ((list = ginGetEntry(&buildstate.accum, &entry, &nlist)) != NULL)
     335            1430 :                 ginEntryInsert(index, &buildstate.ginstate, entry, list, nlist, TRUE);
     336               3 :         MemoryContextSwitchTo(oldCtx);
     337                 : 
     338               3 :         MemoryContextDelete(buildstate.tmpCtx);
     339                 : 
     340                 :         /*
     341                 :          * Return statistics
     342                 :          */
     343               3 :         result = (IndexBuildResult *) palloc(sizeof(IndexBuildResult));
     344                 : 
     345               3 :         result->heap_tuples = reltuples;
     346               3 :         result->index_tuples = buildstate.indtuples;
     347                 : 
     348               3 :         PG_RETURN_POINTER(result);
     349                 : }
     350                 : 
     351                 : /*
     352                 :  * Inserts value during normal insertion
     353                 :  */
     354                 : static uint32
     355                 : ginHeapTupleInsert(Relation index, GinState *ginstate, Datum value, ItemPointer item)
     356               4 : {
     357                 :         Datum      *entries;
     358                 :         int32           i,
     359                 :                                 nentries;
     360                 : 
     361               4 :         entries = extractEntriesSU(ginstate, value, &nentries);
     362                 : 
     363               4 :         if (nentries == 0)
     364                 :                 /* nothing to insert */
     365               1 :                 return 0;
     366                 : 
     367               9 :         for (i = 0; i < nentries; i++)
     368               6 :                 ginEntryInsert(index, ginstate, entries[i], item, 1, FALSE);
     369                 : 
     370               3 :         return nentries;
     371                 : }
     372                 : 
     373                 : Datum
     374                 : gininsert(PG_FUNCTION_ARGS)
     375               4 : {
     376               4 :         Relation        index = (Relation) PG_GETARG_POINTER(0);
     377               4 :         Datum      *values = (Datum *) PG_GETARG_POINTER(1);
     378               4 :         bool       *isnull = (bool *) PG_GETARG_POINTER(2);
     379               4 :         ItemPointer ht_ctid = (ItemPointer) PG_GETARG_POINTER(3);
     380                 : 
     381                 : #ifdef NOT_USED
     382                 :         Relation        heapRel = (Relation) PG_GETARG_POINTER(4);
     383                 :         bool            checkUnique = PG_GETARG_BOOL(5);
     384                 : #endif
     385                 :         GinState        ginstate;
     386                 :         MemoryContext oldCtx;
     387                 :         MemoryContext insertCtx;
     388                 :         uint32          res;
     389                 : 
     390               4 :         if (*isnull)
     391               0 :                 PG_RETURN_BOOL(false);
     392                 : 
     393               4 :         insertCtx = AllocSetContextCreate(CurrentMemoryContext,
     394                 :                                                                           "Gin insert temporary context",
     395                 :                                                                           ALLOCSET_DEFAULT_MINSIZE,
     396                 :                                                                           ALLOCSET_DEFAULT_INITSIZE,
     397                 :                                                                           ALLOCSET_DEFAULT_MAXSIZE);
     398                 : 
     399               4 :         oldCtx = MemoryContextSwitchTo(insertCtx);
     400                 : 
     401               4 :         initGinState(&ginstate, index);
     402                 : 
     403               4 :         res = ginHeapTupleInsert(index, &ginstate, *values, ht_ctid);
     404                 : 
     405               4 :         MemoryContextSwitchTo(oldCtx);
     406               4 :         MemoryContextDelete(insertCtx);
     407                 : 
     408               4 :         PG_RETURN_BOOL(res > 0);
     409                 : }

Generated by: LTP GCOV extension version 1.5