LTP GCOV extension - code coverage report
Current view: directory - access/gin - ginxlog.c
Test: unnamed
Date: 2008-07-03 Instrumented lines: 281
Code covered: 0.0 % Executed lines: 0
Legend: not executed executed

       1                 : /*-------------------------------------------------------------------------
       2                 :  *
       3                 :  * ginxlog.c
       4                 :  *        WAL replay logic for inverted index.
       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/ginxlog.c,v 1.11 2007/11/15 21:14:31 momjian Exp $
      12                 :  *-------------------------------------------------------------------------
      13                 :  */
      14                 : #include "postgres.h"
      15                 : 
      16                 : #include "access/gin.h"
      17                 : #include "access/heapam.h"
      18                 : #include "utils/memutils.h"
      19                 : 
      20                 : static MemoryContext opCtx;             /* working memory for operations */
      21                 : static MemoryContext topCtx;
      22                 : 
      23                 : typedef struct ginIncompleteSplit
      24                 : {
      25                 :         RelFileNode node;
      26                 :         BlockNumber leftBlkno;
      27                 :         BlockNumber rightBlkno;
      28                 :         BlockNumber rootBlkno;
      29                 : } ginIncompleteSplit;
      30                 : 
      31                 : static List *incomplete_splits;
      32                 : 
      33                 : static void
      34                 : pushIncompleteSplit(RelFileNode node, BlockNumber leftBlkno, BlockNumber rightBlkno, BlockNumber rootBlkno)
      35               0 : {
      36                 :         ginIncompleteSplit *split;
      37                 : 
      38               0 :         MemoryContextSwitchTo(topCtx);
      39                 : 
      40               0 :         split = palloc(sizeof(ginIncompleteSplit));
      41                 : 
      42               0 :         split->node = node;
      43               0 :         split->leftBlkno = leftBlkno;
      44               0 :         split->rightBlkno = rightBlkno;
      45               0 :         split->rootBlkno = rootBlkno;
      46                 : 
      47               0 :         incomplete_splits = lappend(incomplete_splits, split);
      48                 : 
      49               0 :         MemoryContextSwitchTo(opCtx);
      50               0 : }
      51                 : 
      52                 : static void
      53                 : forgetIncompleteSplit(RelFileNode node, BlockNumber leftBlkno, BlockNumber updateBlkno)
      54               0 : {
      55                 :         ListCell   *l;
      56                 : 
      57               0 :         foreach(l, incomplete_splits)
      58                 :         {
      59               0 :                 ginIncompleteSplit *split = (ginIncompleteSplit *) lfirst(l);
      60                 : 
      61               0 :                 if (RelFileNodeEquals(node, split->node) && leftBlkno == split->leftBlkno && updateBlkno == split->rightBlkno)
      62                 :                 {
      63               0 :                         incomplete_splits = list_delete_ptr(incomplete_splits, split);
      64               0 :                         break;
      65                 :                 }
      66                 :         }
      67               0 : }
      68                 : 
      69                 : static void
      70                 : ginRedoCreateIndex(XLogRecPtr lsn, XLogRecord *record)
      71               0 : {
      72               0 :         RelFileNode *node = (RelFileNode *) XLogRecGetData(record);
      73                 :         Relation        reln;
      74                 :         Buffer          buffer;
      75                 :         Page            page;
      76                 : 
      77               0 :         reln = XLogOpenRelation(*node);
      78               0 :         buffer = XLogReadBuffer(reln, GIN_ROOT_BLKNO, true);
      79                 :         Assert(BufferIsValid(buffer));
      80               0 :         page = (Page) BufferGetPage(buffer);
      81                 : 
      82               0 :         GinInitBuffer(buffer, GIN_LEAF);
      83                 : 
      84               0 :         PageSetLSN(page, lsn);
      85               0 :         PageSetTLI(page, ThisTimeLineID);
      86                 : 
      87               0 :         MarkBufferDirty(buffer);
      88               0 :         UnlockReleaseBuffer(buffer);
      89               0 : }
      90                 : 
      91                 : static void
      92                 : ginRedoCreatePTree(XLogRecPtr lsn, XLogRecord *record)
      93               0 : {
      94               0 :         ginxlogCreatePostingTree *data = (ginxlogCreatePostingTree *) XLogRecGetData(record);
      95               0 :         ItemPointerData *items = (ItemPointerData *) (XLogRecGetData(record) + sizeof(ginxlogCreatePostingTree));
      96                 :         Relation        reln;
      97                 :         Buffer          buffer;
      98                 :         Page            page;
      99                 : 
     100               0 :         reln = XLogOpenRelation(data->node);
     101               0 :         buffer = XLogReadBuffer(reln, data->blkno, true);
     102                 :         Assert(BufferIsValid(buffer));
     103               0 :         page = (Page) BufferGetPage(buffer);
     104                 : 
     105               0 :         GinInitBuffer(buffer, GIN_DATA | GIN_LEAF);
     106               0 :         memcpy(GinDataPageGetData(page), items, sizeof(ItemPointerData) * data->nitem);
     107               0 :         GinPageGetOpaque(page)->maxoff = data->nitem;
     108                 : 
     109               0 :         PageSetLSN(page, lsn);
     110               0 :         PageSetTLI(page, ThisTimeLineID);
     111                 : 
     112               0 :         MarkBufferDirty(buffer);
     113               0 :         UnlockReleaseBuffer(buffer);
     114               0 : }
     115                 : 
     116                 : static void
     117                 : ginRedoInsert(XLogRecPtr lsn, XLogRecord *record)
     118               0 : {
     119               0 :         ginxlogInsert *data = (ginxlogInsert *) XLogRecGetData(record);
     120                 :         Relation        reln;
     121                 :         Buffer          buffer;
     122                 :         Page            page;
     123                 : 
     124                 :         /* nothing else to do if page was backed up */
     125               0 :         if (record->xl_info & XLR_BKP_BLOCK_1)
     126               0 :                 return;
     127                 : 
     128               0 :         reln = XLogOpenRelation(data->node);
     129               0 :         buffer = XLogReadBuffer(reln, data->blkno, false);
     130                 :         Assert(BufferIsValid(buffer));
     131               0 :         page = (Page) BufferGetPage(buffer);
     132                 : 
     133               0 :         if (data->isData)
     134                 :         {
     135                 :                 Assert(data->isDelete == FALSE);
     136                 :                 Assert(GinPageIsData(page));
     137                 : 
     138               0 :                 if (!XLByteLE(lsn, PageGetLSN(page)))
     139                 :                 {
     140               0 :                         if (data->isLeaf)
     141                 :                         {
     142                 :                                 OffsetNumber i;
     143               0 :                                 ItemPointerData *items = (ItemPointerData *) (XLogRecGetData(record) + sizeof(ginxlogInsert));
     144                 : 
     145                 :                                 Assert(GinPageIsLeaf(page));
     146                 :                                 Assert(data->updateBlkno == InvalidBlockNumber);
     147                 : 
     148               0 :                                 for (i = 0; i < data->nitem; i++)
     149               0 :                                         GinDataPageAddItem(page, items + i, data->offset + i);
     150                 :                         }
     151                 :                         else
     152                 :                         {
     153                 :                                 PostingItem *pitem;
     154                 : 
     155                 :                                 Assert(!GinPageIsLeaf(page));
     156                 : 
     157               0 :                                 if (data->updateBlkno != InvalidBlockNumber)
     158                 :                                 {
     159                 :                                         /* update link to right page after split */
     160               0 :                                         pitem = (PostingItem *) GinDataPageGetItem(page, data->offset);
     161               0 :                                         PostingItemSetBlockNumber(pitem, data->updateBlkno);
     162                 :                                 }
     163                 : 
     164               0 :                                 pitem = (PostingItem *) (XLogRecGetData(record) + sizeof(ginxlogInsert));
     165                 : 
     166               0 :                                 GinDataPageAddItem(page, pitem, data->offset);
     167                 :                         }
     168                 :                 }
     169                 : 
     170               0 :                 if (!data->isLeaf && data->updateBlkno != InvalidBlockNumber)
     171                 :                 {
     172               0 :                         PostingItem *pitem = (PostingItem *) (XLogRecGetData(record) + sizeof(ginxlogInsert));
     173                 : 
     174               0 :                         forgetIncompleteSplit(data->node, PostingItemGetBlockNumber(pitem), data->updateBlkno);
     175                 :                 }
     176                 : 
     177                 :         }
     178                 :         else
     179                 :         {
     180                 :                 IndexTuple      itup;
     181                 : 
     182                 :                 Assert(!GinPageIsData(page));
     183                 : 
     184               0 :                 if (!XLByteLE(lsn, PageGetLSN(page)))
     185                 :                 {
     186               0 :                         if (data->updateBlkno != InvalidBlockNumber)
     187                 :                         {
     188                 :                                 /* update link to right page after split */
     189                 :                                 Assert(!GinPageIsLeaf(page));
     190                 :                                 Assert(data->offset >= FirstOffsetNumber && data->offset <= PageGetMaxOffsetNumber(page));
     191               0 :                                 itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, data->offset));
     192               0 :                                 ItemPointerSet(&itup->t_tid, data->updateBlkno, InvalidOffsetNumber);
     193                 :                         }
     194                 : 
     195               0 :                         if (data->isDelete)
     196                 :                         {
     197                 :                                 Assert(GinPageIsLeaf(page));
     198                 :                                 Assert(data->offset >= FirstOffsetNumber && data->offset <= PageGetMaxOffsetNumber(page));
     199               0 :                                 PageIndexTupleDelete(page, data->offset);
     200                 :                         }
     201                 : 
     202               0 :                         itup = (IndexTuple) (XLogRecGetData(record) + sizeof(ginxlogInsert));
     203                 : 
     204               0 :                         if (PageAddItem(page, (Item) itup, IndexTupleSize(itup), data->offset, false, false) == InvalidOffsetNumber)
     205               0 :                                 elog(ERROR, "failed to add item to index page in %u/%u/%u",
     206                 :                                   data->node.spcNode, data->node.dbNode, data->node.relNode);
     207                 :                 }
     208                 : 
     209               0 :                 if (!data->isLeaf && data->updateBlkno != InvalidBlockNumber)
     210                 :                 {
     211               0 :                         itup = (IndexTuple) (XLogRecGetData(record) + sizeof(ginxlogInsert));
     212               0 :                         forgetIncompleteSplit(data->node, GinItemPointerGetBlockNumber(&itup->t_tid), data->updateBlkno);
     213                 :                 }
     214                 :         }
     215                 : 
     216               0 :         if (!XLByteLE(lsn, PageGetLSN(page)))
     217                 :         {
     218               0 :                 PageSetLSN(page, lsn);
     219               0 :                 PageSetTLI(page, ThisTimeLineID);
     220                 : 
     221               0 :                 MarkBufferDirty(buffer);
     222                 :         }
     223               0 :         UnlockReleaseBuffer(buffer);
     224                 : }
     225                 : 
     226                 : static void
     227                 : ginRedoSplit(XLogRecPtr lsn, XLogRecord *record)
     228               0 : {
     229               0 :         ginxlogSplit *data = (ginxlogSplit *) XLogRecGetData(record);
     230                 :         Relation        reln;
     231                 :         Buffer          lbuffer,
     232                 :                                 rbuffer;
     233                 :         Page            lpage,
     234                 :                                 rpage;
     235               0 :         uint32          flags = 0;
     236                 : 
     237               0 :         reln = XLogOpenRelation(data->node);
     238                 : 
     239               0 :         if (data->isLeaf)
     240               0 :                 flags |= GIN_LEAF;
     241               0 :         if (data->isData)
     242               0 :                 flags |= GIN_DATA;
     243                 : 
     244               0 :         lbuffer = XLogReadBuffer(reln, data->lblkno, data->isRootSplit);
     245                 :         Assert(BufferIsValid(lbuffer));
     246               0 :         lpage = (Page) BufferGetPage(lbuffer);
     247               0 :         GinInitBuffer(lbuffer, flags);
     248                 : 
     249               0 :         rbuffer = XLogReadBuffer(reln, data->rblkno, true);
     250                 :         Assert(BufferIsValid(rbuffer));
     251               0 :         rpage = (Page) BufferGetPage(rbuffer);
     252               0 :         GinInitBuffer(rbuffer, flags);
     253                 : 
     254               0 :         GinPageGetOpaque(lpage)->rightlink = BufferGetBlockNumber(rbuffer);
     255               0 :         GinPageGetOpaque(rpage)->rightlink = data->rrlink;
     256                 : 
     257               0 :         if (data->isData)
     258                 :         {
     259               0 :                 char       *ptr = XLogRecGetData(record) + sizeof(ginxlogSplit);
     260               0 :                 Size            sizeofitem = GinSizeOfItem(lpage);
     261                 :                 OffsetNumber i;
     262                 :                 ItemPointer bound;
     263                 : 
     264               0 :                 for (i = 0; i < data->separator; i++)
     265                 :                 {
     266               0 :                         GinDataPageAddItem(lpage, ptr, InvalidOffsetNumber);
     267               0 :                         ptr += sizeofitem;
     268                 :                 }
     269                 : 
     270               0 :                 for (i = data->separator; i < data->nitem; i++)
     271                 :                 {
     272               0 :                         GinDataPageAddItem(rpage, ptr, InvalidOffsetNumber);
     273               0 :                         ptr += sizeofitem;
     274                 :                 }
     275                 : 
     276                 :                 /* set up right key */
     277               0 :                 bound = GinDataPageGetRightBound(lpage);
     278               0 :                 if (data->isLeaf)
     279               0 :                         *bound = *(ItemPointerData *) GinDataPageGetItem(lpage, GinPageGetOpaque(lpage)->maxoff);
     280                 :                 else
     281               0 :                         *bound = ((PostingItem *) GinDataPageGetItem(lpage, GinPageGetOpaque(lpage)->maxoff))->key;
     282                 : 
     283               0 :                 bound = GinDataPageGetRightBound(rpage);
     284               0 :                 *bound = data->rightbound;
     285                 :         }
     286                 :         else
     287                 :         {
     288               0 :                 IndexTuple      itup = (IndexTuple) (XLogRecGetData(record) + sizeof(ginxlogSplit));
     289                 :                 OffsetNumber i;
     290                 : 
     291               0 :                 for (i = 0; i < data->separator; i++)
     292                 :                 {
     293               0 :                         if (PageAddItem(lpage, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, false, false) == InvalidOffsetNumber)
     294               0 :                                 elog(ERROR, "failed to add item to index page in %u/%u/%u",
     295                 :                                   data->node.spcNode, data->node.dbNode, data->node.relNode);
     296               0 :                         itup = (IndexTuple) (((char *) itup) + MAXALIGN(IndexTupleSize(itup)));
     297                 :                 }
     298                 : 
     299               0 :                 for (i = data->separator; i < data->nitem; i++)
     300                 :                 {
     301               0 :                         if (PageAddItem(rpage, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, false, false) == InvalidOffsetNumber)
     302               0 :                                 elog(ERROR, "failed to add item to index page in %u/%u/%u",
     303                 :                                   data->node.spcNode, data->node.dbNode, data->node.relNode);
     304               0 :                         itup = (IndexTuple) (((char *) itup) + MAXALIGN(IndexTupleSize(itup)));
     305                 :                 }
     306                 :         }
     307                 : 
     308               0 :         PageSetLSN(rpage, lsn);
     309               0 :         PageSetTLI(rpage, ThisTimeLineID);
     310               0 :         MarkBufferDirty(rbuffer);
     311                 : 
     312               0 :         PageSetLSN(lpage, lsn);
     313               0 :         PageSetTLI(lpage, ThisTimeLineID);
     314               0 :         MarkBufferDirty(lbuffer);
     315                 : 
     316               0 :         if (!data->isLeaf && data->updateBlkno != InvalidBlockNumber)
     317               0 :                 forgetIncompleteSplit(data->node, data->leftChildBlkno, data->updateBlkno);
     318                 : 
     319               0 :         if (data->isRootSplit)
     320                 :         {
     321               0 :                 Buffer          rootBuf = XLogReadBuffer(reln, data->rootBlkno, false);
     322               0 :                 Page            rootPage = BufferGetPage(rootBuf);
     323                 : 
     324               0 :                 GinInitBuffer(rootBuf, flags & ~GIN_LEAF);
     325                 : 
     326               0 :                 if (data->isData)
     327                 :                 {
     328                 :                         Assert(data->rootBlkno != GIN_ROOT_BLKNO);
     329               0 :                         dataFillRoot(NULL, rootBuf, lbuffer, rbuffer);
     330                 :                 }
     331                 :                 else
     332                 :                 {
     333                 :                         Assert(data->rootBlkno == GIN_ROOT_BLKNO);
     334               0 :                         entryFillRoot(NULL, rootBuf, lbuffer, rbuffer);
     335                 :                 }
     336                 : 
     337               0 :                 PageSetLSN(rootPage, lsn);
     338               0 :                 PageSetTLI(rootPage, ThisTimeLineID);
     339                 : 
     340               0 :                 MarkBufferDirty(rootBuf);
     341               0 :                 UnlockReleaseBuffer(rootBuf);
     342                 :         }
     343                 :         else
     344               0 :                 pushIncompleteSplit(data->node, data->lblkno, data->rblkno, data->rootBlkno);
     345                 : 
     346               0 :         UnlockReleaseBuffer(rbuffer);
     347               0 :         UnlockReleaseBuffer(lbuffer);
     348               0 : }
     349                 : 
     350                 : static void
     351                 : ginRedoVacuumPage(XLogRecPtr lsn, XLogRecord *record)
     352               0 : {
     353               0 :         ginxlogVacuumPage *data = (ginxlogVacuumPage *) XLogRecGetData(record);
     354                 :         Relation        reln;
     355                 :         Buffer          buffer;
     356                 :         Page            page;
     357                 : 
     358                 :         /* nothing else to do if page was backed up (and no info to do it with) */
     359               0 :         if (record->xl_info & XLR_BKP_BLOCK_1)
     360               0 :                 return;
     361                 : 
     362               0 :         reln = XLogOpenRelation(data->node);
     363               0 :         buffer = XLogReadBuffer(reln, data->blkno, false);
     364                 :         Assert(BufferIsValid(buffer));
     365               0 :         page = (Page) BufferGetPage(buffer);
     366                 : 
     367               0 :         if (GinPageIsData(page))
     368                 :         {
     369               0 :                 memcpy(GinDataPageGetData(page), XLogRecGetData(record) + sizeof(ginxlogVacuumPage),
     370                 :                            GinSizeOfItem(page) *data->nitem);
     371               0 :                 GinPageGetOpaque(page)->maxoff = data->nitem;
     372                 :         }
     373                 :         else
     374                 :         {
     375                 :                 OffsetNumber i,
     376                 :                                    *tod;
     377               0 :                 IndexTuple      itup = (IndexTuple) (XLogRecGetData(record) + sizeof(ginxlogVacuumPage));
     378                 : 
     379               0 :                 tod = (OffsetNumber *) palloc(sizeof(OffsetNumber) * PageGetMaxOffsetNumber(page));
     380               0 :                 for (i = FirstOffsetNumber; i <= PageGetMaxOffsetNumber(page); i++)
     381               0 :                         tod[i - 1] = i;
     382                 : 
     383               0 :                 PageIndexMultiDelete(page, tod, PageGetMaxOffsetNumber(page));
     384                 : 
     385               0 :                 for (i = 0; i < data->nitem; i++)
     386                 :                 {
     387               0 :                         if (PageAddItem(page, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, false, false) == InvalidOffsetNumber)
     388               0 :                                 elog(ERROR, "failed to add item to index page in %u/%u/%u",
     389                 :                                   data->node.spcNode, data->node.dbNode, data->node.relNode);
     390               0 :                         itup = (IndexTuple) (((char *) itup) + MAXALIGN(IndexTupleSize(itup)));
     391                 :                 }
     392                 :         }
     393                 : 
     394               0 :         PageSetLSN(page, lsn);
     395               0 :         PageSetTLI(page, ThisTimeLineID);
     396                 : 
     397               0 :         MarkBufferDirty(buffer);
     398               0 :         UnlockReleaseBuffer(buffer);
     399                 : }
     400                 : 
     401                 : static void
     402                 : ginRedoDeletePage(XLogRecPtr lsn, XLogRecord *record)
     403               0 : {
     404               0 :         ginxlogDeletePage *data = (ginxlogDeletePage *) XLogRecGetData(record);
     405                 :         Relation        reln;
     406                 :         Buffer          buffer;
     407                 :         Page            page;
     408                 : 
     409               0 :         reln = XLogOpenRelation(data->node);
     410                 : 
     411               0 :         if (!(record->xl_info & XLR_BKP_BLOCK_1))
     412                 :         {
     413               0 :                 buffer = XLogReadBuffer(reln, data->blkno, false);
     414               0 :                 page = BufferGetPage(buffer);
     415                 :                 Assert(GinPageIsData(page));
     416               0 :                 GinPageGetOpaque(page)->flags = GIN_DELETED;
     417               0 :                 PageSetLSN(page, lsn);
     418               0 :                 PageSetTLI(page, ThisTimeLineID);
     419               0 :                 MarkBufferDirty(buffer);
     420               0 :                 UnlockReleaseBuffer(buffer);
     421                 :         }
     422                 : 
     423               0 :         if (!(record->xl_info & XLR_BKP_BLOCK_2))
     424                 :         {
     425               0 :                 buffer = XLogReadBuffer(reln, data->parentBlkno, false);
     426               0 :                 page = BufferGetPage(buffer);
     427                 :                 Assert(GinPageIsData(page));
     428                 :                 Assert(!GinPageIsLeaf(page));
     429               0 :                 PageDeletePostingItem(page, data->parentOffset);
     430               0 :                 PageSetLSN(page, lsn);
     431               0 :                 PageSetTLI(page, ThisTimeLineID);
     432               0 :                 MarkBufferDirty(buffer);
     433               0 :                 UnlockReleaseBuffer(buffer);
     434                 :         }
     435                 : 
     436               0 :         if (!(record->xl_info & XLR_BKP_BLOCK_3) && data->leftBlkno != InvalidBlockNumber)
     437                 :         {
     438               0 :                 buffer = XLogReadBuffer(reln, data->leftBlkno, false);
     439               0 :                 page = BufferGetPage(buffer);
     440                 :                 Assert(GinPageIsData(page));
     441               0 :                 GinPageGetOpaque(page)->rightlink = data->rightLink;
     442               0 :                 PageSetLSN(page, lsn);
     443               0 :                 PageSetTLI(page, ThisTimeLineID);
     444               0 :                 MarkBufferDirty(buffer);
     445               0 :                 UnlockReleaseBuffer(buffer);
     446                 :         }
     447               0 : }
     448                 : 
     449                 : void
     450                 : gin_redo(XLogRecPtr lsn, XLogRecord *record)
     451               0 : {
     452               0 :         uint8           info = record->xl_info & ~XLR_INFO_MASK;
     453                 : 
     454               0 :         topCtx = MemoryContextSwitchTo(opCtx);
     455               0 :         switch (info)
     456                 :         {
     457                 :                 case XLOG_GIN_CREATE_INDEX:
     458               0 :                         ginRedoCreateIndex(lsn, record);
     459               0 :                         break;
     460                 :                 case XLOG_GIN_CREATE_PTREE:
     461               0 :                         ginRedoCreatePTree(lsn, record);
     462               0 :                         break;
     463                 :                 case XLOG_GIN_INSERT:
     464               0 :                         ginRedoInsert(lsn, record);
     465               0 :                         break;
     466                 :                 case XLOG_GIN_SPLIT:
     467               0 :                         ginRedoSplit(lsn, record);
     468               0 :                         break;
     469                 :                 case XLOG_GIN_VACUUM_PAGE:
     470               0 :                         ginRedoVacuumPage(lsn, record);
     471               0 :                         break;
     472                 :                 case XLOG_GIN_DELETE_PAGE:
     473               0 :                         ginRedoDeletePage(lsn, record);
     474               0 :                         break;
     475                 :                 default:
     476               0 :                         elog(PANIC, "gin_redo: unknown op code %u", info);
     477                 :         }
     478               0 :         MemoryContextSwitchTo(topCtx);
     479               0 :         MemoryContextReset(opCtx);
     480               0 : }
     481                 : 
     482                 : static void
     483                 : desc_node(StringInfo buf, RelFileNode node, BlockNumber blkno)
     484               0 : {
     485               0 :         appendStringInfo(buf, "node: %u/%u/%u blkno: %u",
     486                 :                                          node.spcNode, node.dbNode, node.relNode, blkno);
     487               0 : }
     488                 : 
     489                 : void
     490                 : gin_desc(StringInfo buf, uint8 xl_info, char *rec)
     491               0 : {
     492               0 :         uint8           info = xl_info & ~XLR_INFO_MASK;
     493                 : 
     494               0 :         switch (info)
     495                 :         {
     496                 :                 case XLOG_GIN_CREATE_INDEX:
     497               0 :                         appendStringInfo(buf, "Create index, ");
     498               0 :                         desc_node(buf, *(RelFileNode *) rec, GIN_ROOT_BLKNO);
     499               0 :                         break;
     500                 :                 case XLOG_GIN_CREATE_PTREE:
     501               0 :                         appendStringInfo(buf, "Create posting tree, ");
     502               0 :                         desc_node(buf, ((ginxlogCreatePostingTree *) rec)->node, ((ginxlogCreatePostingTree *) rec)->blkno);
     503               0 :                         break;
     504                 :                 case XLOG_GIN_INSERT:
     505               0 :                         appendStringInfo(buf, "Insert item, ");
     506               0 :                         desc_node(buf, ((ginxlogInsert *) rec)->node, ((ginxlogInsert *) rec)->blkno);
     507               0 :                         appendStringInfo(buf, " offset: %u nitem: %u isdata: %c isleaf %c isdelete %c updateBlkno:%u",
     508                 :                                                          ((ginxlogInsert *) rec)->offset,
     509                 :                                                          ((ginxlogInsert *) rec)->nitem,
     510                 :                                                          (((ginxlogInsert *) rec)->isData) ? 'T' : 'F',
     511                 :                                                          (((ginxlogInsert *) rec)->isLeaf) ? 'T' : 'F',
     512                 :                                                          (((ginxlogInsert *) rec)->isDelete) ? 'T' : 'F',
     513                 :                                                          ((ginxlogInsert *) rec)->updateBlkno
     514                 :                                 );
     515                 : 
     516               0 :                         break;
     517                 :                 case XLOG_GIN_SPLIT:
     518               0 :                         appendStringInfo(buf, "Page split, ");
     519               0 :                         desc_node(buf, ((ginxlogSplit *) rec)->node, ((ginxlogSplit *) rec)->lblkno);
     520               0 :                         appendStringInfo(buf, " isrootsplit: %c", (((ginxlogSplit *) rec)->isRootSplit) ? 'T' : 'F');
     521               0 :                         break;
     522                 :                 case XLOG_GIN_VACUUM_PAGE:
     523               0 :                         appendStringInfo(buf, "Vacuum page, ");
     524               0 :                         desc_node(buf, ((ginxlogVacuumPage *) rec)->node, ((ginxlogVacuumPage *) rec)->blkno);
     525               0 :                         break;
     526                 :                 case XLOG_GIN_DELETE_PAGE:
     527               0 :                         appendStringInfo(buf, "Delete page, ");
     528               0 :                         desc_node(buf, ((ginxlogDeletePage *) rec)->node, ((ginxlogDeletePage *) rec)->blkno);
     529               0 :                         break;
     530                 :                 default:
     531               0 :                         elog(PANIC, "gin_desc: unknown op code %u", info);
     532                 :         }
     533               0 : }
     534                 : 
     535                 : void
     536                 : gin_xlog_startup(void)
     537               0 : {
     538               0 :         incomplete_splits = NIL;
     539                 : 
     540               0 :         opCtx = AllocSetContextCreate(CurrentMemoryContext,
     541                 :                                                                   "GIN recovery temporary context",
     542                 :                                                                   ALLOCSET_DEFAULT_MINSIZE,
     543                 :                                                                   ALLOCSET_DEFAULT_INITSIZE,
     544                 :                                                                   ALLOCSET_DEFAULT_MAXSIZE);
     545               0 : }
     546                 : 
     547                 : static void
     548                 : ginContinueSplit(ginIncompleteSplit *split)
     549               0 : {
     550                 :         GinBtreeData btree;
     551                 :         Relation        reln;
     552                 :         Buffer          buffer;
     553                 :         GinBtreeStack stack;
     554                 : 
     555                 :         /*
     556                 :          * elog(NOTICE,"ginContinueSplit root:%u l:%u r:%u",  split->rootBlkno,
     557                 :          * split->leftBlkno, split->rightBlkno);
     558                 :          */
     559               0 :         reln = XLogOpenRelation(split->node);
     560                 : 
     561               0 :         buffer = XLogReadBuffer(reln, split->leftBlkno, false);
     562                 : 
     563               0 :         if (split->rootBlkno == GIN_ROOT_BLKNO)
     564                 :         {
     565               0 :                 prepareEntryScan(&btree, reln, (Datum) 0, NULL);
     566               0 :                 btree.entry = ginPageGetLinkItup(buffer);
     567                 :         }
     568                 :         else
     569                 :         {
     570               0 :                 Page            page = BufferGetPage(buffer);
     571                 : 
     572               0 :                 prepareDataScan(&btree, reln);
     573                 : 
     574               0 :                 PostingItemSetBlockNumber(&(btree.pitem), split->leftBlkno);
     575               0 :                 if (GinPageIsLeaf(page))
     576               0 :                         btree.pitem.key = *(ItemPointerData *) GinDataPageGetItem(page,
     577                 :                                                                                          GinPageGetOpaque(page)->maxoff);
     578                 :                 else
     579               0 :                         btree.pitem.key = ((PostingItem *) GinDataPageGetItem(page,
     580                 :                                                                            GinPageGetOpaque(page)->maxoff))->key;
     581                 :         }
     582                 : 
     583               0 :         btree.rightblkno = split->rightBlkno;
     584                 : 
     585               0 :         stack.blkno = split->leftBlkno;
     586               0 :         stack.buffer = buffer;
     587               0 :         stack.off = InvalidOffsetNumber;
     588               0 :         stack.parent = NULL;
     589                 : 
     590               0 :         findParents(&btree, &stack, split->rootBlkno);
     591               0 :         ginInsertValue(&btree, stack.parent);
     592                 : 
     593               0 :         UnlockReleaseBuffer(buffer);
     594               0 : }
     595                 : 
     596                 : void
     597                 : gin_xlog_cleanup(void)
     598               0 : {
     599                 :         ListCell   *l;
     600                 :         MemoryContext topCtx;
     601                 : 
     602               0 :         topCtx = MemoryContextSwitchTo(opCtx);
     603                 : 
     604               0 :         foreach(l, incomplete_splits)
     605                 :         {
     606               0 :                 ginIncompleteSplit *split = (ginIncompleteSplit *) lfirst(l);
     607                 : 
     608               0 :                 ginContinueSplit(split);
     609               0 :                 MemoryContextReset(opCtx);
     610                 :         }
     611                 : 
     612               0 :         MemoryContextSwitchTo(topCtx);
     613               0 :         MemoryContextDelete(opCtx);
     614               0 :         incomplete_splits = NIL;
     615               0 : }
     616                 : 
     617                 : bool
     618                 : gin_safe_restartpoint(void)
     619               0 : {
     620               0 :         if (incomplete_splits)
     621               0 :                 return false;
     622               0 :         return true;
     623                 : }

Generated by: LTP GCOV extension version 1.5