Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

einige Melodien

Quelle  ginxlog.c

  Sprache: C
 

/*-------------------------------------------------------------------------
 *
 * ginxlog.c
 *   WAL replay logic for inverted index.
 *
 *
 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * IDENTIFICATION
 *    src/backend/access/gin/ginxlog.c
 *-------------------------------------------------------------------------
 */

#include "postgres.h"

#include "access/bufmask.h"
#include "access/gin_private.h"
#include "access/ginxlog.h"
#include "access/xlogutils.h"
#include "utils/memutils.h"

static MemoryContext opCtx;  /* working memory for operations */

static void
ginRedoClearIncompleteSplit(XLogReaderState *record, uint8 block_id)
{
 XLogRecPtr lsn = record->EndRecPtr;
 Buffer  buffer;
 Page  page;

 if (XLogReadBufferForRedo(record, block_id, &buffer) == BLK_NEEDS_REDO)
 {
  page = (Page) BufferGetPage(buffer);
  GinPageGetOpaque(page)->flags &= ~GIN_INCOMPLETE_SPLIT;

  PageSetLSN(page, lsn);
  MarkBufferDirty(buffer);
 }
 if (BufferIsValid(buffer))
  UnlockReleaseBuffer(buffer);
}

static void
ginRedoCreatePTree(XLogReaderState *record)
{
 XLogRecPtr lsn = record->EndRecPtr;
 ginxlogCreatePostingTree *data = (ginxlogCreatePostingTree *) XLogRecGetData(record);
 char    *ptr;
 Buffer  buffer;
 Page  page;

 buffer = XLogInitBufferForRedo(record, 0);
 page = (Page) BufferGetPage(buffer);

 GinInitBuffer(buffer, GIN_DATA | GIN_LEAF | GIN_COMPRESSED);

 ptr = XLogRecGetData(record) + sizeof(ginxlogCreatePostingTree);

 /* Place page data */
 memcpy(GinDataLeafPageGetPostingList(page), ptr, data->size);

 GinDataPageSetDataSize(page, data->size);

 PageSetLSN(page, lsn);

 MarkBufferDirty(buffer);
 UnlockReleaseBuffer(buffer);
}

static void
ginRedoInsertEntry(Buffer buffer, bool isLeaf, BlockNumber rightblkno, void *rdata)
{
 Page  page = BufferGetPage(buffer);
 ginxlogInsertEntry *data = (ginxlogInsertEntry *) rdata;
 OffsetNumber offset = data->offset;
 IndexTuple itup;

 if (rightblkno != InvalidBlockNumber)
 {
  /* update link to right page after split */
  Assert(!GinPageIsLeaf(page));
  Assert(offset >= FirstOffsetNumber && offset <= PageGetMaxOffsetNumber(page));
  itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offset));
  GinSetDownlink(itup, rightblkno);
 }

 if (data->isDelete)
 {
  Assert(GinPageIsLeaf(page));
  Assert(offset >= FirstOffsetNumber && offset <= PageGetMaxOffsetNumber(page));
  PageIndexTupleDelete(page, offset);
 }

 itup = &data->tuple;

 if (PageAddItem(page, (Item) itup, IndexTupleSize(itup), offset, falsefalse) == InvalidOffsetNumber)
 {
  RelFileLocator locator;
  ForkNumber forknum;
  BlockNumber blknum;

  BufferGetTag(buffer, &locator, &forknum, &blknum);
  elog(ERROR, "failed to add item to index page in %u/%u/%u",
    locator.spcOid, locator.dbOid, locator.relNumber);
 }
}

/*
 * Redo recompression of posting list.  Doing all the changes in-place is not
 * always possible, because it might require more space than we've on the page.
 * Instead, once modification is required we copy unprocessed tail of the page
 * into separately allocated chunk of memory for further reading original
 * versions of segments.  Thanks to that we don't bother about moving page data
 * in-place.
 */

static void
ginRedoRecompress(Page page, ginxlogRecompressDataLeaf *data)
{
 int   actionno;
 int   segno;
 GinPostingList *oldseg;
 Pointer  segmentend;
 char    *walbuf;
 int   totalsize;
 Pointer  tailCopy = NULL;
 Pointer  writePtr;
 Pointer  segptr;

 /*
  * If the page is in pre-9.4 format, convert to new format first.
 */

 if (!GinPageIsCompressed(page))
 {
  ItemPointer uncompressed = (ItemPointer) GinDataPageGetData(page);
  int   nuncompressed = GinPageGetOpaque(page)->maxoff;
  int   npacked;

  /*
   * Empty leaf pages are deleted as part of vacuum, but leftmost and
   * rightmost pages are never deleted.  So, pg_upgrade'd from pre-9.4
   * instances might contain empty leaf pages, and we need to handle
   * them correctly.
 */

  if (nuncompressed > 0)
  {
   GinPostingList *plist;

   plist = ginCompressPostingList(uncompressed, nuncompressed,
             BLCKSZ, &npacked);
   totalsize = SizeOfGinPostingList(plist);

   Assert(npacked == nuncompressed);

   memcpy(GinDataLeafPageGetPostingList(page), plist, totalsize);
  }
  else
  {
   totalsize = 0;
  }

  GinDataPageSetDataSize(page, totalsize);
  GinPageSetCompressed(page);
  GinPageGetOpaque(page)->maxoff = InvalidOffsetNumber;
 }

 oldseg = GinDataLeafPageGetPostingList(page);
 writePtr = (Pointer) oldseg;
 segmentend = (Pointer) oldseg + GinDataLeafPageGetPostingListSize(page);
 segno = 0;

 walbuf = ((char *) data) + sizeof(ginxlogRecompressDataLeaf);
 for (actionno = 0; actionno < data->nactions; actionno++)
 {
  uint8  a_segno = *((uint8 *) (walbuf++));
  uint8  a_action = *((uint8 *) (walbuf++));
  GinPostingList *newseg = NULL;
  int   newsegsize = 0;
  ItemPointerData *items = NULL;
  uint16  nitems = 0;
  ItemPointerData *olditems;
  int   nolditems;
  ItemPointerData *newitems;
  int   nnewitems;
  int   segsize;

  /* Extract all the information we need from the WAL record */
  if (a_action == GIN_SEGMENT_INSERT ||
   a_action == GIN_SEGMENT_REPLACE)
  {
   newseg = (GinPostingList *) walbuf;
   newsegsize = SizeOfGinPostingList(newseg);
   walbuf += SHORTALIGN(newsegsize);
  }

  if (a_action == GIN_SEGMENT_ADDITEMS)
  {
   memcpy(&nitems, walbuf, sizeof(uint16));
   walbuf += sizeof(uint16);
   items = (ItemPointerData *) walbuf;
   walbuf += nitems * sizeof(ItemPointerData);
  }

  /* Skip to the segment that this action concerns */
  Assert(segno <= a_segno);
  while (segno < a_segno)
  {
   /*
    * Once modification is started and page tail is copied, we've to
    * copy unmodified segments.
 */

   segsize = SizeOfGinPostingList(oldseg);
   if (tailCopy)
   {
    Assert(writePtr + segsize < PageGetSpecialPointer(page));
    memcpy(writePtr, (Pointer) oldseg, segsize);
   }
   writePtr += segsize;
   oldseg = GinNextPostingListSegment(oldseg);
   segno++;
  }

  /*
   * ADDITEMS action is handled like REPLACE, but the new segment to
   * replace the old one is reconstructed using the old segment from
   * disk and the new items from the WAL record.
 */

  if (a_action == GIN_SEGMENT_ADDITEMS)
  {
   int   npacked;

   olditems = ginPostingListDecode(oldseg, &nolditems);

   newitems = ginMergeItemPointers(items, nitems,
           olditems, nolditems,
           &nnewitems);
   Assert(nnewitems == nolditems + nitems);

   newseg = ginCompressPostingList(newitems, nnewitems,
           BLCKSZ, &npacked);
   Assert(npacked == nnewitems);

   newsegsize = SizeOfGinPostingList(newseg);
   a_action = GIN_SEGMENT_REPLACE;
  }

  segptr = (Pointer) oldseg;
  if (segptr != segmentend)
   segsize = SizeOfGinPostingList(oldseg);
  else
  {
   /*
    * Positioned after the last existing segment. Only INSERTs
    * expected here.
 */

   Assert(a_action == GIN_SEGMENT_INSERT);
   segsize = 0;
  }

  /*
   * We're about to start modification of the page.  So, copy tail of
   * the page if it's not done already.
 */

  if (!tailCopy && segptr != segmentend)
  {
   int   tailSize = segmentend - segptr;

   tailCopy = (Pointer) palloc(tailSize);
   memcpy(tailCopy, segptr, tailSize);
   segptr = tailCopy;
   oldseg = (GinPostingList *) segptr;
   segmentend = segptr + tailSize;
  }

  switch (a_action)
  {
   case GIN_SEGMENT_DELETE:
    segptr += segsize;
    segno++;
    break;

   case GIN_SEGMENT_INSERT:
    /* copy the new segment in place */
    Assert(writePtr + newsegsize <= PageGetSpecialPointer(page));
    memcpy(writePtr, newseg, newsegsize);
    writePtr += newsegsize;
    break;

   case GIN_SEGMENT_REPLACE:
    /* copy the new version of segment in place */
    Assert(writePtr + newsegsize <= PageGetSpecialPointer(page));
    memcpy(writePtr, newseg, newsegsize);
    writePtr += newsegsize;
    segptr += segsize;
    segno++;
    break;

   default:
    elog(ERROR, "unexpected GIN leaf action: %u", a_action);
  }
  oldseg = (GinPostingList *) segptr;
 }

 /* Copy the rest of unmodified segments if any. */
 segptr = (Pointer) oldseg;
 if (segptr != segmentend && tailCopy)
 {
  int   restSize = segmentend - segptr;

  Assert(writePtr + restSize <= PageGetSpecialPointer(page));
  memcpy(writePtr, segptr, restSize);
  writePtr += restSize;
 }

 totalsize = writePtr - (Pointer) GinDataLeafPageGetPostingList(page);
 GinDataPageSetDataSize(page, totalsize);
}

static void
ginRedoInsertData(Buffer buffer, bool isLeaf, BlockNumber rightblkno, void *rdata)
{
 Page  page = BufferGetPage(buffer);

 if (isLeaf)
 {
  ginxlogRecompressDataLeaf *data = (ginxlogRecompressDataLeaf *) rdata;

  Assert(GinPageIsLeaf(page));

  ginRedoRecompress(page, data);
 }
 else
 {
  ginxlogInsertDataInternal *data = (ginxlogInsertDataInternal *) rdata;
  PostingItem *oldpitem;

  Assert(!GinPageIsLeaf(page));

  /* update link to right page after split */
  oldpitem = GinDataPageGetPostingItem(page, data->offset);
  PostingItemSetBlockNumber(oldpitem, rightblkno);

  GinDataPageAddPostingItem(page, &data->newitem, data->offset);
 }
}

static void
ginRedoInsert(XLogReaderState *record)
{
 XLogRecPtr lsn = record->EndRecPtr;
 ginxlogInsert *data = (ginxlogInsert *) XLogRecGetData(record);
 Buffer  buffer;
#ifdef NOT_USED
 BlockNumber leftChildBlkno = InvalidBlockNumber;
#endif
 BlockNumber rightChildBlkno = InvalidBlockNumber;
 bool  isLeaf = (data->flags & GIN_INSERT_ISLEAF) != 0;

 /*
  * First clear incomplete-split flag on child page if this finishes a
  * split.
 */

 if (!isLeaf)
 {
  char    *payload = XLogRecGetData(record) + sizeof(ginxlogInsert);

#ifdef NOT_USED
  leftChildBlkno = BlockIdGetBlockNumber((BlockId) payload);
#endif
  payload += sizeof(BlockIdData);
  rightChildBlkno = BlockIdGetBlockNumber((BlockId) payload);
  payload += sizeof(BlockIdData);

  ginRedoClearIncompleteSplit(record, 1);
 }

 if (XLogReadBufferForRedo(record, 0, &buffer) == BLK_NEEDS_REDO)
 {
  Page  page = BufferGetPage(buffer);
  Size  len;
  char    *payload = XLogRecGetBlockData(record, 0, &len);

  /* How to insert the payload is tree-type specific */
  if (data->flags & GIN_INSERT_ISDATA)
  {
   Assert(GinPageIsData(page));
   ginRedoInsertData(buffer, isLeaf, rightChildBlkno, payload);
  }
  else
  {
   Assert(!GinPageIsData(page));
   ginRedoInsertEntry(buffer, isLeaf, rightChildBlkno, payload);
  }

  PageSetLSN(page, lsn);
  MarkBufferDirty(buffer);
 }
 if (BufferIsValid(buffer))
  UnlockReleaseBuffer(buffer);
}

static void
ginRedoSplit(XLogReaderState *record)
{
 ginxlogSplit *data = (ginxlogSplit *) XLogRecGetData(record);
 Buffer  lbuffer,
    rbuffer,
    rootbuf;
 bool  isLeaf = (data->flags & GIN_INSERT_ISLEAF) != 0;
 bool  isRoot = (data->flags & GIN_SPLIT_ROOT) != 0;

 /*
  * First clear incomplete-split flag on child page if this finishes a
  * split
 */

 if (!isLeaf)
  ginRedoClearIncompleteSplit(record, 3);

 if (XLogReadBufferForRedo(record, 0, &lbuffer) != BLK_RESTORED)
  elog(ERROR, "GIN split record did not contain a full-page image of left page");

 if (XLogReadBufferForRedo(record, 1, &rbuffer) != BLK_RESTORED)
  elog(ERROR, "GIN split record did not contain a full-page image of right page");

 if (isRoot)
 {
  if (XLogReadBufferForRedo(record, 2, &rootbuf) != BLK_RESTORED)
   elog(ERROR, "GIN split record did not contain a full-page image of root page");
  UnlockReleaseBuffer(rootbuf);
 }

 UnlockReleaseBuffer(rbuffer);
 UnlockReleaseBuffer(lbuffer);
}

/*
 * VACUUM_PAGE record contains simply a full image of the page, similar to
 * an XLOG_FPI record.
 */

static void
ginRedoVacuumPage(XLogReaderState *record)
{
 Buffer  buffer;

 if (XLogReadBufferForRedo(record, 0, &buffer) != BLK_RESTORED)
 {
  elog(ERROR, "replay of gin entry tree page vacuum did not restore the page");
 }
 UnlockReleaseBuffer(buffer);
}

static void
ginRedoVacuumDataLeafPage(XLogReaderState *record)
{
 XLogRecPtr lsn = record->EndRecPtr;
 Buffer  buffer;

 if (XLogReadBufferForRedo(record, 0, &buffer) == BLK_NEEDS_REDO)
 {
  Page  page = BufferGetPage(buffer);
  Size  len;
  ginxlogVacuumDataLeafPage *xlrec;

  xlrec = (ginxlogVacuumDataLeafPage *) XLogRecGetBlockData(record, 0, &len);

  Assert(GinPageIsLeaf(page));
  Assert(GinPageIsData(page));

  ginRedoRecompress(page, &xlrec->data);
  PageSetLSN(page, lsn);
  MarkBufferDirty(buffer);
 }
 if (BufferIsValid(buffer))
  UnlockReleaseBuffer(buffer);
}

static void
ginRedoDeletePage(XLogReaderState *record)
{
 XLogRecPtr lsn = record->EndRecPtr;
 ginxlogDeletePage *data = (ginxlogDeletePage *) XLogRecGetData(record);
 Buffer  dbuffer;
 Buffer  pbuffer;
 Buffer  lbuffer;
 Page  page;

 /*
  * Lock left page first in order to prevent possible deadlock with
  * ginStepRight().
 */

 if (XLogReadBufferForRedo(record, 2, &lbuffer) == BLK_NEEDS_REDO)
 {
  page = BufferGetPage(lbuffer);
  Assert(GinPageIsData(page));
  GinPageGetOpaque(page)->rightlink = data->rightLink;
  PageSetLSN(page, lsn);
  MarkBufferDirty(lbuffer);
 }

 if (XLogReadBufferForRedo(record, 0, &dbuffer) == BLK_NEEDS_REDO)
 {
  page = BufferGetPage(dbuffer);
  Assert(GinPageIsData(page));
  GinPageSetDeleted(page);
  GinPageSetDeleteXid(page, data->deleteXid);
  PageSetLSN(page, lsn);
  MarkBufferDirty(dbuffer);
 }

 if (XLogReadBufferForRedo(record, 1, &pbuffer) == BLK_NEEDS_REDO)
 {
  page = BufferGetPage(pbuffer);
  Assert(GinPageIsData(page));
  Assert(!GinPageIsLeaf(page));
  GinPageDeletePostingItem(page, data->parentOffset);
  PageSetLSN(page, lsn);
  MarkBufferDirty(pbuffer);
 }

 if (BufferIsValid(lbuffer))
  UnlockReleaseBuffer(lbuffer);
 if (BufferIsValid(pbuffer))
  UnlockReleaseBuffer(pbuffer);
 if (BufferIsValid(dbuffer))
  UnlockReleaseBuffer(dbuffer);
}

static void
ginRedoUpdateMetapage(XLogReaderState *record)
{
 XLogRecPtr lsn = record->EndRecPtr;
 ginxlogUpdateMeta *data = (ginxlogUpdateMeta *) XLogRecGetData(record);
 Buffer  metabuffer;
 Page  metapage;
 Buffer  buffer;

 /*
  * Restore the metapage. This is essentially the same as a full-page
  * image, so restore the metapage unconditionally without looking at the
  * LSN, to avoid torn page hazards.
 */

 metabuffer = XLogInitBufferForRedo(record, 0);
 Assert(BufferGetBlockNumber(metabuffer) == GIN_METAPAGE_BLKNO);
 metapage = BufferGetPage(metabuffer);

 GinInitMetabuffer(metabuffer);
 memcpy(GinPageGetMeta(metapage), &data->metadata, sizeof(GinMetaPageData));
 PageSetLSN(metapage, lsn);
 MarkBufferDirty(metabuffer);

 if (data->ntuples > 0)
 {
  /*
   * insert into tail page
 */

  if (XLogReadBufferForRedo(record, 1, &buffer) == BLK_NEEDS_REDO)
  {
   Page  page = BufferGetPage(buffer);
   OffsetNumber off;
   int   i;
   Size  tupsize;
   char    *payload;
   IndexTuple tuples;
   Size  totaltupsize;

   payload = XLogRecGetBlockData(record, 1, &totaltupsize);
   tuples = (IndexTuple) payload;

   if (PageIsEmpty(page))
    off = FirstOffsetNumber;
   else
    off = OffsetNumberNext(PageGetMaxOffsetNumber(page));

   for (i = 0; i < data->ntuples; i++)
   {
    tupsize = IndexTupleSize(tuples);

    if (PageAddItem(page, (Item) tuples, tupsize, off,
        falsefalse) == InvalidOffsetNumber)
     elog(ERROR, "failed to add item to index page");

    tuples = (IndexTuple) (((char *) tuples) + tupsize);

    off++;
   }
   Assert(payload + totaltupsize == (char *) tuples);

   /*
    * Increase counter of heap tuples
 */

   GinPageGetOpaque(page)->maxoff++;

   PageSetLSN(page, lsn);
   MarkBufferDirty(buffer);
  }
  if (BufferIsValid(buffer))
   UnlockReleaseBuffer(buffer);
 }
 else if (data->prevTail != InvalidBlockNumber)
 {
  /*
   * New tail
 */

  if (XLogReadBufferForRedo(record, 1, &buffer) == BLK_NEEDS_REDO)
  {
   Page  page = BufferGetPage(buffer);

   GinPageGetOpaque(page)->rightlink = data->newRightlink;

   PageSetLSN(page, lsn);
   MarkBufferDirty(buffer);
  }
  if (BufferIsValid(buffer))
   UnlockReleaseBuffer(buffer);
 }

 UnlockReleaseBuffer(metabuffer);
}

static void
ginRedoInsertListPage(XLogReaderState *record)
{
 XLogRecPtr lsn = record->EndRecPtr;
 ginxlogInsertListPage *data = (ginxlogInsertListPage *) XLogRecGetData(record);
 Buffer  buffer;
 Page  page;
 OffsetNumber l,
    off = FirstOffsetNumber;
 int   i,
    tupsize;
 char    *payload;
 IndexTuple tuples;
 Size  totaltupsize;

 /* We always re-initialize the page. */
 buffer = XLogInitBufferForRedo(record, 0);
 page = BufferGetPage(buffer);

 GinInitBuffer(buffer, GIN_LIST);
 GinPageGetOpaque(page)->rightlink = data->rightlink;
 if (data->rightlink == InvalidBlockNumber)
 {
  /* tail of sublist */
  GinPageSetFullRow(page);
  GinPageGetOpaque(page)->maxoff = 1;
 }
 else
 {
  GinPageGetOpaque(page)->maxoff = 0;
 }

 payload = XLogRecGetBlockData(record, 0, &totaltupsize);

 tuples = (IndexTuple) payload;
 for (i = 0; i < data->ntuples; i++)
 {
  tupsize = IndexTupleSize(tuples);

  l = PageAddItem(page, (Item) tuples, tupsize, off, falsefalse);

  if (l == InvalidOffsetNumber)
   elog(ERROR, "failed to add item to index page");

  tuples = (IndexTuple) (((char *) tuples) + tupsize);
  off++;
 }
 Assert((char *) tuples == payload + totaltupsize);

 PageSetLSN(page, lsn);
 MarkBufferDirty(buffer);

 UnlockReleaseBuffer(buffer);
}

static void
ginRedoDeleteListPages(XLogReaderState *record)
{
 XLogRecPtr lsn = record->EndRecPtr;
 ginxlogDeleteListPages *data = (ginxlogDeleteListPages *) XLogRecGetData(record);
 Buffer  metabuffer;
 Page  metapage;
 int   i;

 metabuffer = XLogInitBufferForRedo(record, 0);
 Assert(BufferGetBlockNumber(metabuffer) == GIN_METAPAGE_BLKNO);
 metapage = BufferGetPage(metabuffer);

 GinInitMetabuffer(metabuffer);

 memcpy(GinPageGetMeta(metapage), &data->metadata, sizeof(GinMetaPageData));
 PageSetLSN(metapage, lsn);
 MarkBufferDirty(metabuffer);

 /*
  * In normal operation, shiftList() takes exclusive lock on all the
  * pages-to-be-deleted simultaneously.  During replay, however, it should
  * be all right to lock them one at a time.  This is dependent on the fact
  * that we are deleting pages from the head of the list, and that readers
  * share-lock the next page before releasing the one they are on. So we
  * cannot get past a reader that is on, or due to visit, any page we are
  * going to delete.  New incoming readers will block behind our metapage
  * lock and then see a fully updated page list.
  *
  * No full-page images are taken of the deleted pages. Instead, they are
  * re-initialized as empty, deleted pages. Their right-links don't need to
  * be preserved, because no new readers can see the pages, as explained
  * above.
 */

 for (i = 0; i < data->ndeleted; i++)
 {
  Buffer  buffer;
  Page  page;

  buffer = XLogInitBufferForRedo(record, i + 1);
  page = BufferGetPage(buffer);
  GinInitBuffer(buffer, GIN_DELETED);

  PageSetLSN(page, lsn);
  MarkBufferDirty(buffer);

  UnlockReleaseBuffer(buffer);
 }
 UnlockReleaseBuffer(metabuffer);
}

void
gin_redo(XLogReaderState *record)
{
 uint8  info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
 MemoryContext oldCtx;

 /*
  * GIN indexes do not require any conflict processing. NB: If we ever
  * implement a similar optimization as we have in b-tree, and remove
  * killed tuples outside VACUUM, we'll need to handle that here.
 */


 oldCtx = MemoryContextSwitchTo(opCtx);
 switch (info)
 {
  case XLOG_GIN_CREATE_PTREE:
   ginRedoCreatePTree(record);
   break;
  case XLOG_GIN_INSERT:
   ginRedoInsert(record);
   break;
  case XLOG_GIN_SPLIT:
   ginRedoSplit(record);
   break;
  case XLOG_GIN_VACUUM_PAGE:
   ginRedoVacuumPage(record);
   break;
  case XLOG_GIN_VACUUM_DATA_LEAF_PAGE:
   ginRedoVacuumDataLeafPage(record);
   break;
  case XLOG_GIN_DELETE_PAGE:
   ginRedoDeletePage(record);
   break;
  case XLOG_GIN_UPDATE_META_PAGE:
   ginRedoUpdateMetapage(record);
   break;
  case XLOG_GIN_INSERT_LISTPAGE:
   ginRedoInsertListPage(record);
   break;
  case XLOG_GIN_DELETE_LISTPAGE:
   ginRedoDeleteListPages(record);
   break;
  default:
   elog(PANIC, "gin_redo: unknown op code %u", info);
 }
 MemoryContextSwitchTo(oldCtx);
 MemoryContextReset(opCtx);
}

void
gin_xlog_startup(void)
{
 opCtx = AllocSetContextCreate(CurrentMemoryContext,
          "GIN recovery temporary context",
          ALLOCSET_DEFAULT_SIZES);
}

void
gin_xlog_cleanup(void)
{
 MemoryContextDelete(opCtx);
 opCtx = NULL;
}

/*
 * Mask a GIN page before running consistency checks on it.
 */

void
gin_mask(char *pagedata, BlockNumber blkno)
{
 Page  page = (Page) pagedata;
 PageHeader pagehdr = (PageHeader) page;
 GinPageOpaque opaque;

 mask_page_lsn_and_checksum(page);
 opaque = GinPageGetOpaque(page);

 mask_page_hint_bits(page);

 /*
  * For a GIN_DELETED page, the page is initialized to empty.  Hence, mask
  * the whole page content.  For other pages, mask the hole if pd_lower
  * appears to have been set correctly.
 */

 if (opaque->flags & GIN_DELETED)
  mask_page_content(page);
 else if (pagehdr->pd_lower > SizeOfPageHeaderData)
  mask_unused_space(page);
}

Messung V0.5 in Prozent
C=95 H=94 G=94

¤ Dauer der Verarbeitung: 0.3 Sekunden  (vorverarbeitet am  2026-08-08) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=141584
#Domains=752002