LTP GCOV extension - code coverage report
Current view: directory - access/gin - ginget.c
Test: unnamed
Date: 2008-07-03 Instrumented lines: 223
Code covered: 69.1 % Executed lines: 154
Legend: not executed executed

       1                 : /*-------------------------------------------------------------------------
       2                 :  *
       3                 :  * ginget.c
       4                 :  *        fetch tuples from a GIN scan.
       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/ginget.c,v 1.9 2007/11/15 21:14:31 momjian Exp $
      12                 :  *-------------------------------------------------------------------------
      13                 :  */
      14                 : 
      15                 : #include "postgres.h"
      16                 : #include "access/gin.h"
      17                 : #include "catalog/index.h"
      18                 : #include "utils/memutils.h"
      19                 : 
      20                 : static bool
      21                 : findItemInPage(Page page, ItemPointer item, OffsetNumber *off)
      22             237 : {
      23             237 :         OffsetNumber maxoff = GinPageGetOpaque(page)->maxoff;
      24                 :         int                     res;
      25                 : 
      26             237 :         if (GinPageGetOpaque(page)->flags & GIN_DELETED)
      27                 :                 /* page was deleted by concurrent  vacuum */
      28               0 :                 return false;
      29                 : 
      30             237 :         if (*off > maxoff || *off == InvalidOffsetNumber)
      31               0 :                 res = -1;
      32                 :         else
      33             237 :                 res = compareItemPointers(item, (ItemPointer) GinDataPageGetItem(page, *off));
      34                 : 
      35             237 :         if (res == 0)
      36                 :         {
      37                 :                 /* page isn't changed */
      38             237 :                 return true;
      39                 :         }
      40               0 :         else if (res > 0)
      41                 :         {
      42                 :                 /*
      43                 :                  * some items was added before our position, look further to find it
      44                 :                  * or first greater
      45                 :                  */
      46                 : 
      47               0 :                 (*off)++;
      48               0 :                 for (; *off <= maxoff; (*off)++)
      49                 :                 {
      50               0 :                         res = compareItemPointers(item, (ItemPointer) GinDataPageGetItem(page, *off));
      51                 : 
      52               0 :                         if (res == 0)
      53               0 :                                 return true;
      54                 : 
      55               0 :                         if (res < 0)
      56                 :                         {
      57               0 :                                 (*off)--;
      58               0 :                                 return true;
      59                 :                         }
      60                 :                 }
      61                 :         }
      62                 :         else
      63                 :         {
      64                 :                 /*
      65                 :                  * some items was deleted before our position, look from begining to
      66                 :                  * find it or first greater
      67                 :                  */
      68                 : 
      69               0 :                 for (*off = FirstOffsetNumber; *off <= maxoff; (*off)++)
      70                 :                 {
      71               0 :                         res = compareItemPointers(item, (ItemPointer) GinDataPageGetItem(page, *off));
      72                 : 
      73               0 :                         if (res == 0)
      74               0 :                                 return true;
      75                 : 
      76               0 :                         if (res < 0)
      77                 :                         {
      78               0 :                                 (*off)--;
      79               0 :                                 return true;
      80                 :                         }
      81                 :                 }
      82                 :         }
      83                 : 
      84               0 :         return false;
      85                 : }
      86                 : 
      87                 : /*
      88                 :  * Start* functions setup state of searches: find correct buffer and locks it,
      89                 :  * Stop* functions unlock buffer (but don't release!)
      90                 :  */
      91                 : static void
      92                 : startScanEntry(Relation index, GinState *ginstate, GinScanEntry entry, bool firstCall)
      93            1162 : {
      94            1162 :         if (entry->master != NULL)
      95                 :         {
      96               0 :                 entry->isFinished = entry->master->isFinished;
      97               0 :                 return;
      98                 :         }
      99                 : 
     100            1162 :         if (firstCall)
     101                 :         {
     102                 :                 /*
     103                 :                  * at first call we should find entry, and begin scan of posting tree
     104                 :                  * or just store posting list in memory
     105                 :                  */
     106                 :                 GinBtreeData btreeEntry;
     107                 :                 GinBtreeStack *stackEntry;
     108                 :                 Page            page;
     109              54 :                 bool            needUnlock = TRUE;
     110                 : 
     111              54 :                 prepareEntryScan(&btreeEntry, index, entry->entry, ginstate);
     112              54 :                 btreeEntry.searchMode = TRUE;
     113              54 :                 stackEntry = ginFindLeafPage(&btreeEntry, NULL);
     114              54 :                 page = BufferGetPage(stackEntry->buffer);
     115                 : 
     116              54 :                 entry->isFinished = TRUE;
     117              54 :                 entry->buffer = InvalidBuffer;
     118              54 :                 entry->offset = InvalidOffsetNumber;
     119              54 :                 entry->list = NULL;
     120              54 :                 entry->nlist = 0;
     121              54 :                 entry->reduceResult = FALSE;
     122              54 :                 entry->predictNumberResult = 0;
     123                 : 
     124              54 :                 if (btreeEntry.findItem(&btreeEntry, stackEntry))
     125                 :                 {
     126              52 :                         IndexTuple      itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, stackEntry->off));
     127                 : 
     128              52 :                         if (GinIsPostingTree(itup))
     129                 :                         {
     130               4 :                                 BlockNumber rootPostingTree = GinGetPostingTree(itup);
     131                 :                                 GinPostingTreeScan *gdi;
     132                 :                                 Page            page;
     133                 : 
     134               4 :                                 LockBuffer(stackEntry->buffer, GIN_UNLOCK);
     135               4 :                                 needUnlock = FALSE;
     136               4 :                                 gdi = prepareScanPostingTree(index, rootPostingTree, TRUE);
     137                 : 
     138               4 :                                 entry->buffer = scanBeginPostingTree(gdi);
     139               4 :                                 IncrBufferRefCount(entry->buffer);
     140                 : 
     141               4 :                                 page = BufferGetPage(entry->buffer);
     142               4 :                                 entry->predictNumberResult = gdi->stack->predictNumber * GinPageGetOpaque(page)->maxoff;
     143                 : 
     144               4 :                                 freeGinBtreeStack(gdi->stack);
     145               4 :                                 pfree(gdi);
     146               4 :                                 entry->isFinished = FALSE;
     147                 :                         }
     148              48 :                         else if (GinGetNPosting(itup) > 0)
     149                 :                         {
     150              48 :                                 entry->nlist = GinGetNPosting(itup);
     151              48 :                                 entry->list = (ItemPointerData *) palloc(sizeof(ItemPointerData) * entry->nlist);
     152              48 :                                 memcpy(entry->list, GinGetPosting(itup), sizeof(ItemPointerData) * entry->nlist);
     153              48 :                                 entry->isFinished = FALSE;
     154                 :                         }
     155                 :                 }
     156                 : 
     157              54 :                 if (needUnlock)
     158              50 :                         LockBuffer(stackEntry->buffer, GIN_UNLOCK);
     159              54 :                 freeGinBtreeStack(stackEntry);
     160                 :         }
     161            1108 :         else if (entry->buffer != InvalidBuffer)
     162                 :         {
     163                 :                 /* we should find place where we was stopped */
     164                 :                 BlockNumber blkno;
     165                 :                 Page            page;
     166                 : 
     167             237 :                 LockBuffer(entry->buffer, GIN_SHARE);
     168                 : 
     169             237 :                 if (!ItemPointerIsValid(&entry->curItem))
     170                 :                         /* start position */
     171               0 :                         return;
     172                 :                 Assert(entry->offset != InvalidOffsetNumber);
     173                 : 
     174             237 :                 page = BufferGetPage(entry->buffer);
     175                 : 
     176                 :                 /* try to find curItem in current buffer */
     177             237 :                 if (findItemInPage(page, &entry->curItem, &entry->offset))
     178             237 :                         return;
     179                 : 
     180                 :                 /* walk to right */
     181               0 :                 while ((blkno = GinPageGetOpaque(page)->rightlink) != InvalidBlockNumber)
     182                 :                 {
     183               0 :                         LockBuffer(entry->buffer, GIN_UNLOCK);
     184               0 :                         entry->buffer = ReleaseAndReadBuffer(entry->buffer, index, blkno);
     185               0 :                         LockBuffer(entry->buffer, GIN_SHARE);
     186               0 :                         page = BufferGetPage(entry->buffer);
     187                 : 
     188               0 :                         entry->offset = InvalidOffsetNumber;
     189               0 :                         if (findItemInPage(page, &entry->curItem, &entry->offset))
     190               0 :                                 return;
     191                 :                 }
     192                 : 
     193                 :                 /*
     194                 :                  * curItem and any greated items was deleted by concurrent vacuum, so
     195                 :                  * we finished scan with currrent entry
     196                 :                  */
     197                 :         }
     198                 : }
     199                 : 
     200                 : static void
     201                 : stopScanEntry(GinScanEntry entry)
     202            1162 : {
     203            1162 :         if (entry->buffer != InvalidBuffer)
     204             237 :                 LockBuffer(entry->buffer, GIN_UNLOCK);
     205            1162 : }
     206                 : 
     207                 : static void
     208                 : startScanKey(Relation index, GinState *ginstate, GinScanKey key)
     209             478 : {
     210                 :         uint32          i;
     211                 : 
     212            1640 :         for (i = 0; i < key->nentries; i++)
     213            1162 :                 startScanEntry(index, ginstate, key->scanEntry + i, key->firstCall);
     214                 : 
     215             478 :         if (key->firstCall)
     216                 :         {
     217              26 :                 memset(key->entryRes, TRUE, sizeof(bool) * key->nentries);
     218              26 :                 key->isFinished = FALSE;
     219              26 :                 key->firstCall = FALSE;
     220                 : 
     221              26 :                 if (GinFuzzySearchLimit > 0)
     222                 :                 {
     223                 :                         /*
     224                 :                          * If all of keys more than threshold we will try to reduce
     225                 :                          * result, we hope (and only hope, for intersection operation of
     226                 :                          * array our supposition isn't true), that total result will not
     227                 :                          * more than minimal predictNumberResult.
     228                 :                          */
     229                 : 
     230               0 :                         for (i = 0; i < key->nentries; i++)
     231               0 :                                 if (key->scanEntry[i].predictNumberResult <= key->nentries * GinFuzzySearchLimit)
     232               0 :                                         return;
     233                 : 
     234               0 :                         for (i = 0; i < key->nentries; i++)
     235               0 :                                 if (key->scanEntry[i].predictNumberResult > key->nentries * GinFuzzySearchLimit)
     236                 :                                 {
     237               0 :                                         key->scanEntry[i].predictNumberResult /= key->nentries;
     238               0 :                                         key->scanEntry[i].reduceResult = TRUE;
     239                 :                                 }
     240                 :                 }
     241                 :         }
     242                 : }
     243                 : 
     244                 : static void
     245                 : stopScanKey(GinScanKey key)
     246             478 : {
     247                 :         uint32          i;
     248                 : 
     249            1640 :         for (i = 0; i < key->nentries; i++)
     250            1162 :                 stopScanEntry(key->scanEntry + i);
     251             478 : }
     252                 : 
     253                 : static void
     254                 : startScan(IndexScanDesc scan)
     255             478 : {
     256                 :         uint32          i;
     257             478 :         GinScanOpaque so = (GinScanOpaque) scan->opaque;
     258                 : 
     259             956 :         for (i = 0; i < so->nkeys; i++)
     260             478 :                 startScanKey(scan->indexRelation, &so->ginstate, so->keys + i);
     261             478 : }
     262                 : 
     263                 : static void
     264                 : stopScan(IndexScanDesc scan)
     265             478 : {
     266                 :         uint32          i;
     267             478 :         GinScanOpaque so = (GinScanOpaque) scan->opaque;
     268                 : 
     269             956 :         for (i = 0; i < so->nkeys; i++)
     270             478 :                 stopScanKey(so->keys + i);
     271             478 : }
     272                 : 
     273                 : 
     274                 : static void
     275                 : entryGetNextItem(Relation index, GinScanEntry entry)
     276             396 : {
     277             396 :         Page            page = BufferGetPage(entry->buffer);
     278                 : 
     279             396 :         entry->offset++;
     280             788 :         if (entry->offset <= GinPageGetOpaque(page)->maxoff && GinPageGetOpaque(page)->maxoff >= FirstOffsetNumber)
     281                 :         {
     282             392 :                 entry->curItem = *(ItemPointerData *) GinDataPageGetItem(page, entry->offset);
     283                 :         }
     284                 :         else
     285                 :         {
     286               4 :                 BlockNumber blkno = GinPageGetOpaque(page)->rightlink;
     287                 : 
     288               4 :                 LockBuffer(entry->buffer, GIN_UNLOCK);
     289               4 :                 if (blkno == InvalidBlockNumber)
     290                 :                 {
     291               4 :                         ReleaseBuffer(entry->buffer);
     292               4 :                         entry->buffer = InvalidBuffer;
     293               4 :                         entry->isFinished = TRUE;
     294                 :                 }
     295                 :                 else
     296                 :                 {
     297               0 :                         entry->buffer = ReleaseAndReadBuffer(entry->buffer, index, blkno);
     298               0 :                         LockBuffer(entry->buffer, GIN_SHARE);
     299               0 :                         entry->offset = InvalidOffsetNumber;
     300               0 :                         entryGetNextItem(index, entry);
     301                 :                 }
     302                 :         }
     303             396 : }
     304                 : 
     305                 : #define gin_rand() (((double) random()) / ((double) MAX_RANDOM_VALUE))
     306                 : #define dropItem(e) ( gin_rand() > ((double)GinFuzzySearchLimit)/((double)((e)->predictNumberResult)) )
     307                 : 
     308                 : /*
     309                 :  * Sets entry->curItem to new found heap item pointer for one
     310                 :  * entry of one scan key
     311                 :  */
     312                 : static bool
     313                 : entryGetItem(Relation index, GinScanEntry entry)
     314            1330 : {
     315            1330 :         if (entry->master)
     316                 :         {
     317               0 :                 entry->isFinished = entry->master->isFinished;
     318               0 :                 entry->curItem = entry->master->curItem;
     319                 :         }
     320            1330 :         else if (entry->list)
     321                 :         {
     322             934 :                 entry->offset++;
     323             934 :                 if (entry->offset <= entry->nlist)
     324             886 :                         entry->curItem = entry->list[entry->offset - 1];
     325                 :                 else
     326                 :                 {
     327              48 :                         ItemPointerSet(&entry->curItem, InvalidBlockNumber, InvalidOffsetNumber);
     328              48 :                         entry->isFinished = TRUE;
     329                 :                 }
     330                 :         }
     331                 :         else
     332                 :         {
     333                 :                 do
     334                 :                 {
     335             396 :                         entryGetNextItem(index, entry);
     336             396 :                 } while (entry->isFinished == FALSE && entry->reduceResult == TRUE && dropItem(entry));
     337                 :         }
     338                 : 
     339            1330 :         return entry->isFinished;
     340                 : }
     341                 : 
     342                 : /*
     343                 :  * Sets key->curItem to new found heap item pointer for one scan key
     344                 :  * returns isFinished!
     345                 :  */
     346                 : static bool
     347                 : keyGetItem(Relation index, GinState *ginstate, MemoryContext tempCtx, GinScanKey key)
     348             478 : {
     349                 :         uint32          i;
     350                 :         GinScanEntry entry;
     351                 :         bool            res;
     352                 :         MemoryContext oldCtx;
     353                 : 
     354             478 :         if (key->isFinished)
     355               0 :                 return TRUE;
     356                 : 
     357                 :         do
     358                 :         {
     359                 :                 /*
     360                 :                  * move forward from previously value and set new curItem, which is
     361                 :                  * minimal from entries->curItems
     362                 :                  */
     363            1108 :                 ItemPointerSetMax(&key->curItem);
     364            4274 :                 for (i = 0; i < key->nentries; i++)
     365                 :                 {
     366            3166 :                         entry = key->scanEntry + i;
     367                 : 
     368            3166 :                         if (key->entryRes[i])
     369                 :                         {
     370            1332 :                                 if (entry->isFinished == FALSE && entryGetItem(index, entry) == FALSE)
     371                 :                                 {
     372            1278 :                                         if (compareItemPointers(&entry->curItem, &key->curItem) < 0)
     373             820 :                                                 key->curItem = entry->curItem;
     374                 :                                 }
     375                 :                                 else
     376              54 :                                         key->entryRes[i] = FALSE;
     377                 :                         }
     378            1834 :                         else if (entry->isFinished == FALSE)
     379                 :                         {
     380            1785 :                                 if (compareItemPointers(&entry->curItem, &key->curItem) < 0)
     381             830 :                                         key->curItem = entry->curItem;
     382                 :                         }
     383                 :                 }
     384                 : 
     385            1108 :                 if (ItemPointerIsMax(&key->curItem))
     386                 :                 {
     387                 :                         /* all entries are finished */
     388              26 :                         key->isFinished = TRUE;
     389              26 :                         return TRUE;
     390                 :                 }
     391                 : 
     392            1082 :                 if (key->nentries == 1)
     393                 :                 {
     394                 :                         /* we can do not call consistentFn !! */
     395              42 :                         key->entryRes[0] = TRUE;
     396              42 :                         return FALSE;
     397                 :                 }
     398                 : 
     399                 :                 /* setting up array for consistentFn */
     400            4110 :                 for (i = 0; i < key->nentries; i++)
     401                 :                 {
     402            3070 :                         entry = key->scanEntry + i;
     403                 : 
     404            4306 :                         if (entry->isFinished == FALSE && compareItemPointers(&entry->curItem, &key->curItem) == 0)
     405            1236 :                                 key->entryRes[i] = TRUE;
     406                 :                         else
     407            1834 :                                 key->entryRes[i] = FALSE;
     408                 :                 }
     409                 : 
     410            1040 :                 oldCtx = MemoryContextSwitchTo(tempCtx);
     411            1040 :                 res = DatumGetBool(FunctionCall3(
     412                 :                                                                                  &ginstate->consistentFn,
     413                 :                                                                                  PointerGetDatum(key->entryRes),
     414                 :                                                                                  UInt16GetDatum(key->strategy),
     415                 :                                                                                  key->query
     416                 :                                                                                  ));
     417                 :                 MemoryContextSwitchTo(oldCtx);
     418            1040 :                 MemoryContextReset(tempCtx);
     419            1040 :         } while (!res);
     420                 : 
     421             410 :         return FALSE;
     422                 : }
     423                 : 
     424                 : /*
     425                 :  * Get heap item pointer from scan
     426                 :  * returns true if found
     427                 :  */
     428                 : static bool
     429                 : scanGetItem(IndexScanDesc scan, ItemPointerData *item)
     430             478 : {
     431                 :         uint32          i;
     432             478 :         GinScanOpaque so = (GinScanOpaque) scan->opaque;
     433                 : 
     434             478 :         ItemPointerSetMin(item);
     435             930 :         for (i = 0; i < so->nkeys; i++)
     436                 :         {
     437             478 :                 GinScanKey      key = so->keys + i;
     438                 : 
     439             478 :                 if (keyGetItem(scan->indexRelation, &so->ginstate, so->tempCtx, key) == FALSE)
     440                 :                 {
     441             452 :                         if (compareItemPointers(item, &key->curItem) < 0)
     442             452 :                                 *item = key->curItem;
     443                 :                 }
     444                 :                 else
     445              26 :                         return FALSE;           /* finished one of keys */
     446                 :         }
     447                 : 
     448             904 :         for (i = 1; i <= so->nkeys; i++)
     449                 :         {
     450             452 :                 GinScanKey      key = so->keys + i - 1;
     451                 : 
     452                 :                 for (;;)
     453                 :                 {
     454             452 :                         int                     cmp = compareItemPointers(item, &key->curItem);
     455                 : 
     456             452 :                         if (cmp == 0)
     457             452 :                                 break;
     458               0 :                         else if (cmp > 0)
     459                 :                         {
     460               0 :                                 if (keyGetItem(scan->indexRelation, &so->ginstate, so->tempCtx, key) == TRUE)
     461               0 :                                         return FALSE;           /* finished one of keys */
     462                 :                         }
     463                 :                         else
     464                 :                         {                                       /* returns to begin */
     465               0 :                                 *item = key->curItem;
     466               0 :                                 i = 0;
     467               0 :                                 break;
     468                 :                         }
     469                 :                 }
     470                 :         }
     471                 : 
     472             452 :         return TRUE;
     473                 : }
     474                 : 
     475                 : #define GinIsNewKey(s)          ( ((GinScanOpaque) scan->opaque)->keys == NULL )
     476                 : #define GinIsVoidRes(s)         ( ((GinScanOpaque) scan->opaque)->isVoidRes == true )
     477                 : 
     478                 : Datum
     479                 : gingetmulti(PG_FUNCTION_ARGS)
     480               0 : {
     481               0 :         IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
     482               0 :         ItemPointer tids = (ItemPointer) PG_GETARG_POINTER(1);
     483               0 :         int32           max_tids = PG_GETARG_INT32(2);
     484               0 :         int32      *returned_tids = (int32 *) PG_GETARG_POINTER(3);
     485                 : 
     486               0 :         if (GinIsNewKey(scan))
     487               0 :                 newScanKey(scan);
     488                 : 
     489               0 :         *returned_tids = 0;
     490                 : 
     491               0 :         if (GinIsVoidRes(scan))
     492               0 :                 PG_RETURN_BOOL(false);
     493                 : 
     494               0 :         startScan(scan);
     495                 : 
     496                 :         do
     497                 :         {
     498               0 :                 if (scanGetItem(scan, tids + *returned_tids))
     499               0 :                         (*returned_tids)++;
     500                 :                 else
     501               0 :                         break;
     502               0 :         } while (*returned_tids < max_tids);
     503                 : 
     504               0 :         stopScan(scan);
     505                 : 
     506               0 :         PG_RETURN_BOOL(*returned_tids == max_tids);
     507                 : }
     508                 : 
     509                 : Datum
     510                 : gingettuple(PG_FUNCTION_ARGS)
     511             478 : {
     512             478 :         IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
     513             478 :         ScanDirection dir = (ScanDirection) PG_GETARG_INT32(1);
     514                 :         bool            res;
     515                 : 
     516             478 :         if (dir != ForwardScanDirection)
     517               0 :                 elog(ERROR, "Gin doesn't support other scan directions than forward");
     518                 : 
     519             478 :         if (GinIsNewKey(scan))
     520              26 :                 newScanKey(scan);
     521                 : 
     522             478 :         if (GinIsVoidRes(scan))
     523               0 :                 PG_RETURN_BOOL(false);
     524                 : 
     525             478 :         startScan(scan);
     526             478 :         res = scanGetItem(scan, &scan->xs_ctup.t_self);
     527             478 :         stopScan(scan);
     528                 : 
     529             478 :         PG_RETURN_BOOL(res);
     530                 : }

Generated by: LTP GCOV extension version 1.5