Header And Logo

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

Data Structures | Functions | Variables

gistxlog.c File Reference

#include "postgres.h"
#include "access/gist_private.h"
#include "access/xlogutils.h"
#include "utils/memutils.h"
Include dependency graph for gistxlog.c:

Go to the source code of this file.

Data Structures

struct  NewPage
struct  PageSplitRecord

Functions

static void gistRedoClearFollowRight (XLogRecPtr lsn, XLogRecord *record, int block_index, RelFileNode node, BlockNumber childblkno)
static void gistRedoPageUpdateRecord (XLogRecPtr lsn, XLogRecord *record)
static void decodePageSplitRecord (PageSplitRecord *decoded, XLogRecord *record)
static void gistRedoPageSplitRecord (XLogRecPtr lsn, XLogRecord *record)
static void gistRedoCreateIndex (XLogRecPtr lsn, XLogRecord *record)
void gist_redo (XLogRecPtr lsn, XLogRecord *record)
void gist_xlog_startup (void)
void gist_xlog_cleanup (void)
XLogRecPtr gistXLogSplit (RelFileNode node, BlockNumber blkno, bool page_is_leaf, SplitedPageLayout *dist, BlockNumber origrlink, GistNSN orignsn, Buffer leftchildbuf, bool markfollowright)
XLogRecPtr gistXLogUpdate (RelFileNode node, Buffer buffer, OffsetNumber *todelete, int ntodelete, IndexTuple *itup, int ituplen, Buffer leftchildbuf)

Variables

static MemoryContext opCtx

Function Documentation

static void decodePageSplitRecord ( PageSplitRecord decoded,
XLogRecord record 
) [static]

Definition at line 192 of file gistxlog.c.

References Assert, PageSplitRecord::data, header(), NewPage::header, i, IndexTupleSize, NewPage::itup, gistxlogPageSplit::npage, gistxlogPage::num, PageSplitRecord::page, palloc(), and XLogRecGetData.

Referenced by gistRedoPageSplitRecord().

{
    char       *begin = XLogRecGetData(record),
               *ptr;
    int         j,
                i = 0;

    decoded->data = (gistxlogPageSplit *) begin;
    decoded->page = (NewPage *) palloc(sizeof(NewPage) * decoded->data->npage);

    ptr = begin + sizeof(gistxlogPageSplit);
    for (i = 0; i < decoded->data->npage; i++)
    {
        Assert(ptr - begin < record->xl_len);
        decoded->page[i].header = (gistxlogPage *) ptr;
        ptr += sizeof(gistxlogPage);

        decoded->page[i].itup = (IndexTuple *)
            palloc(sizeof(IndexTuple) * decoded->page[i].header->num);
        j = 0;
        while (j < decoded->page[i].header->num)
        {
            Assert(ptr - begin < record->xl_len);
            decoded->page[i].itup[j] = (IndexTuple) ptr;
            ptr += IndexTupleSize((IndexTuple) ptr);
            j++;
        }
    }
}

void gist_redo ( XLogRecPtr  lsn,
XLogRecord record 
)

Definition at line 330 of file gistxlog.c.

References elog, gistRedoCreateIndex(), gistRedoPageSplitRecord(), gistRedoPageUpdateRecord(), MemoryContextReset(), MemoryContextSwitchTo(), PANIC, XLogRecord::xl_info, XLOG_GIST_CREATE_INDEX, XLOG_GIST_PAGE_SPLIT, and XLOG_GIST_PAGE_UPDATE.

{
    uint8       info = record->xl_info & ~XLR_INFO_MASK;
    MemoryContext oldCxt;

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

    oldCxt = MemoryContextSwitchTo(opCtx);
    switch (info)
    {
        case XLOG_GIST_PAGE_UPDATE:
            gistRedoPageUpdateRecord(lsn, record);
            break;
        case XLOG_GIST_PAGE_SPLIT:
            gistRedoPageSplitRecord(lsn, record);
            break;
        case XLOG_GIST_CREATE_INDEX:
            gistRedoCreateIndex(lsn, record);
            break;
        default:
            elog(PANIC, "gist_redo: unknown op code %u", info);
    }

    MemoryContextSwitchTo(oldCxt);
    MemoryContextReset(opCtx);
}

void gist_xlog_cleanup ( void   ) 

Definition at line 368 of file gistxlog.c.

References MemoryContextDelete().

void gist_xlog_startup ( void   ) 

Definition at line 362 of file gistxlog.c.

References createTempGistContext().

static void gistRedoClearFollowRight ( XLogRecPtr  lsn,
XLogRecord record,
int  block_index,
RelFileNode  node,
BlockNumber  childblkno 
) [static]

Definition at line 46 of file gistxlog.c.

References BufferGetPage, BufferIsValid, GistClearFollowRight, GistPageSetNSN, MarkBufferDirty(), PageGetLSN, PageSetLSN, RestoreBackupBlock(), UnlockReleaseBuffer(), XLogRecord::xl_info, XLogReadBuffer(), and XLR_BKP_BLOCK.

Referenced by gistRedoPageSplitRecord(), and gistRedoPageUpdateRecord().

{
    Buffer      buffer;
    Page        page;

    if (record->xl_info & XLR_BKP_BLOCK(block_index))
        buffer = RestoreBackupBlock(lsn, record, block_index, false, true);
    else
    {
        buffer = XLogReadBuffer(node, childblkno, false);
        if (!BufferIsValid(buffer))
            return;             /* page was deleted, nothing to do */
    }
    page = (Page) BufferGetPage(buffer);

    /*
     * Note that we still update the page even if page LSN is equal to the LSN
     * of this record, because the updated NSN is not included in the full
     * page image.
     */
    if (lsn >= PageGetLSN(page))
    {
        GistPageSetNSN(page, lsn);
        GistClearFollowRight(page);

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

static void gistRedoCreateIndex ( XLogRecPtr  lsn,
XLogRecord record 
) [static]

Definition at line 308 of file gistxlog.c.

References Assert, BufferGetPage, BufferIsValid, F_LEAF, GIST_ROOT_BLKNO, GISTInitBuffer(), MarkBufferDirty(), PageSetLSN, UnlockReleaseBuffer(), XLogRecord::xl_info, XLogReadBuffer(), XLogRecGetData, and XLR_BKP_BLOCK_MASK.

Referenced by gist_redo().

{
    RelFileNode *node = (RelFileNode *) XLogRecGetData(record);
    Buffer      buffer;
    Page        page;

    /* Backup blocks are not used in create_index records */
    Assert(!(record->xl_info & XLR_BKP_BLOCK_MASK));

    buffer = XLogReadBuffer(*node, GIST_ROOT_BLKNO, true);
    Assert(BufferIsValid(buffer));
    page = (Page) BufferGetPage(buffer);

    GISTInitBuffer(buffer, F_LEAF);

    PageSetLSN(page, lsn);

    MarkBufferDirty(buffer);
    UnlockReleaseBuffer(buffer);
}

static void gistRedoPageSplitRecord ( XLogRecPtr  lsn,
XLogRecord record 
) [static]

Definition at line 223 of file gistxlog.c.

References Assert, gistxlogPage::blkno, BlockNumberIsValid, BufferGetPage, BufferIsValid, PageSplitRecord::data, decodePageSplitRecord(), FirstOffsetNumber, GIST_ROOT_BLKNO, GistClearFollowRight, gistfillbuffer(), GISTInitBuffer(), GistMarkFollowRight, GistPageGetOpaque, GistPageSetNSN, gistRedoClearFollowRight(), NewPage::header, i, NewPage::itup, gistxlogPageSplit::leftchild, MarkBufferDirty(), gistxlogPageSplit::markfollowright, gistxlogPageSplit::node, gistxlogPageSplit::npage, gistxlogPage::num, gistxlogPageSplit::origleaf, gistxlogPageSplit::orignsn, gistxlogPageSplit::origrlink, PageSplitRecord::page, PageSetLSN, UnlockReleaseBuffer(), XLogReadBuffer(), and XLogRecGetData.

Referenced by gist_redo().

{
    gistxlogPageSplit *xldata = (gistxlogPageSplit *) XLogRecGetData(record);
    PageSplitRecord xlrec;
    Buffer      firstbuffer = InvalidBuffer;
    Buffer      buffer;
    Page        page;
    int         i;
    bool        isrootsplit = false;

    decodePageSplitRecord(&xlrec, record);

    /*
     * We must hold lock on the first-listed page throughout the action,
     * including while updating the left child page (if any).  We can unlock
     * remaining pages in the list as soon as they've been written, because
     * there is no path for concurrent queries to reach those pages without
     * first visiting the first-listed page.
     */

    /* loop around all pages */
    for (i = 0; i < xlrec.data->npage; i++)
    {
        NewPage    *newpage = xlrec.page + i;
        int         flags;

        if (newpage->header->blkno == GIST_ROOT_BLKNO)
        {
            Assert(i == 0);
            isrootsplit = true;
        }

        buffer = XLogReadBuffer(xlrec.data->node, newpage->header->blkno, true);
        Assert(BufferIsValid(buffer));
        page = (Page) BufferGetPage(buffer);

        /* ok, clear buffer */
        if (xlrec.data->origleaf && newpage->header->blkno != GIST_ROOT_BLKNO)
            flags = F_LEAF;
        else
            flags = 0;
        GISTInitBuffer(buffer, flags);

        /* and fill it */
        gistfillbuffer(page, newpage->itup, newpage->header->num, FirstOffsetNumber);

        if (newpage->header->blkno == GIST_ROOT_BLKNO)
        {
            GistPageGetOpaque(page)->rightlink = InvalidBlockNumber;
            GistPageSetNSN(page, xldata->orignsn);
            GistClearFollowRight(page);
        }
        else
        {
            if (i < xlrec.data->npage - 1)
                GistPageGetOpaque(page)->rightlink = xlrec.page[i + 1].header->blkno;
            else
                GistPageGetOpaque(page)->rightlink = xldata->origrlink;
            GistPageSetNSN(page, xldata->orignsn);
            if (i < xlrec.data->npage - 1 && !isrootsplit &&
                xldata->markfollowright)
                GistMarkFollowRight(page);
            else
                GistClearFollowRight(page);
        }

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

        if (i == 0)
            firstbuffer = buffer;
        else
            UnlockReleaseBuffer(buffer);
    }

    /* Fix follow-right data on left child page, if any */
    if (BlockNumberIsValid(xldata->leftchild))
        gistRedoClearFollowRight(lsn, record, 0,
                                 xldata->node, xldata->leftchild);

    /* Finally, release lock on the first page */
    UnlockReleaseBuffer(firstbuffer);
}

static void gistRedoPageUpdateRecord ( XLogRecPtr  lsn,
XLogRecord record 
) [static]

Definition at line 82 of file gistxlog.c.

References gistxlogPageUpdate::blkno, BlockNumberIsValid, BufferGetPage, BufferIsValid, elog, ERROR, FirstOffsetNumber, GIST_ROOT_BLKNO, GistClearTuplesDeleted, GistMarkTuplesDeleted, GistPageGetOpaque, GistPageIsLeaf, GistPageSetLeaf, gistRedoClearFollowRight(), i, IndexTupleSize, InvalidOffsetNumber, gistxlogPageUpdate::leftchild, MarkBufferDirty(), gistxlogPageUpdate::node, gistxlogPageUpdate::ntodelete, OffsetNumberNext, PageAddItem(), PageGetLSN, PageGetMaxOffsetNumber, PageIndexTupleDelete(), PageIsEmpty, PageSetLSN, RestoreBackupBlock(), UnlockReleaseBuffer(), XLogRecord::xl_info, XLogReadBuffer(), XLogRecGetData, and XLR_BKP_BLOCK.

Referenced by gist_redo().

{
    char       *begin = XLogRecGetData(record);
    gistxlogPageUpdate *xldata = (gistxlogPageUpdate *) begin;
    Buffer      buffer;
    Page        page;
    char       *data;

    /*
     * We need to acquire and hold lock on target page while updating the left
     * child page.  If we have a full-page image of target page, getting the
     * lock is a side-effect of restoring that image.  Note that even if the
     * target page no longer exists, we'll still attempt to replay the change
     * on the child page.
     */
    if (record->xl_info & XLR_BKP_BLOCK(0))
        buffer = RestoreBackupBlock(lsn, record, 0, false, true);
    else
        buffer = XLogReadBuffer(xldata->node, xldata->blkno, false);

    /* Fix follow-right data on left child page */
    if (BlockNumberIsValid(xldata->leftchild))
        gistRedoClearFollowRight(lsn, record, 1,
                                 xldata->node, xldata->leftchild);

    /* Done if target page no longer exists */
    if (!BufferIsValid(buffer))
        return;

    /* nothing more to do if page was backed up (and no info to do it with) */
    if (record->xl_info & XLR_BKP_BLOCK(0))
    {
        UnlockReleaseBuffer(buffer);
        return;
    }

    page = (Page) BufferGetPage(buffer);

    /* nothing more to do if change already applied */
    if (lsn <= PageGetLSN(page))
    {
        UnlockReleaseBuffer(buffer);
        return;
    }

    data = begin + sizeof(gistxlogPageUpdate);

    /* Delete old tuples */
    if (xldata->ntodelete > 0)
    {
        int         i;
        OffsetNumber *todelete = (OffsetNumber *) data;

        data += sizeof(OffsetNumber) * xldata->ntodelete;

        for (i = 0; i < xldata->ntodelete; i++)
            PageIndexTupleDelete(page, todelete[i]);
        if (GistPageIsLeaf(page))
            GistMarkTuplesDeleted(page);
    }

    /* add tuples */
    if (data - begin < record->xl_len)
    {
        OffsetNumber off = (PageIsEmpty(page)) ? FirstOffsetNumber :
        OffsetNumberNext(PageGetMaxOffsetNumber(page));

        while (data - begin < record->xl_len)
        {
            IndexTuple  itup = (IndexTuple) data;
            Size        sz = IndexTupleSize(itup);
            OffsetNumber l;

            data += sz;

            l = PageAddItem(page, (Item) itup, sz, off, false, false);
            if (l == InvalidOffsetNumber)
                elog(ERROR, "failed to add item to GiST index page, size %d bytes",
                     (int) sz);
            off++;
        }
    }
    else
    {
        /*
         * special case: leafpage, nothing to insert, nothing to delete, then
         * vacuum marks page
         */
        if (GistPageIsLeaf(page) && xldata->ntodelete == 0)
            GistClearTuplesDeleted(page);
    }

    if (!GistPageIsLeaf(page) &&
        PageGetMaxOffsetNumber(page) == InvalidOffsetNumber &&
        xldata->blkno == GIST_ROOT_BLKNO)
    {
        /*
         * all links on non-leaf root page was deleted by vacuum full, so root
         * page becomes a leaf
         */
        GistPageSetLeaf(page);
    }

    GistPageGetOpaque(page)->rightlink = InvalidBlockNumber;
    PageSetLSN(page, lsn);
    MarkBufferDirty(buffer);
    UnlockReleaseBuffer(buffer);
}

XLogRecPtr gistXLogSplit ( RelFileNode  node,
BlockNumber  blkno,
bool  page_is_leaf,
SplitedPageLayout dist,
BlockNumber  origrlink,
GistNSN  orignsn,
Buffer  leftchildbuf,
bool  markfollowright 
)

Definition at line 377 of file gistxlog.c.

References SplitedPageLayout::block, XLogRecData::buffer, XLogRecData::buffer_std, BufferGetBlockNumber(), BufferIsValid, cur, XLogRecData::data, gistxlogPageSplit::leftchild, XLogRecData::len, SplitedPageLayout::lenlist, SplitedPageLayout::list, gistxlogPageSplit::markfollowright, XLogRecData::next, SplitedPageLayout::next, gistxlogPageSplit::node, gistxlogPageSplit::npage, gistxlogPageSplit::origblkno, gistxlogPageSplit::origleaf, gistxlogPageSplit::orignsn, gistxlogPageSplit::origrlink, palloc(), pfree(), XLOG_GIST_PAGE_SPLIT, and XLogInsert().

Referenced by gistplacetopage().

{
    XLogRecData *rdata;
    gistxlogPageSplit xlrec;
    SplitedPageLayout *ptr;
    int         npage = 0,
                cur;
    XLogRecPtr  recptr;

    for (ptr = dist; ptr; ptr = ptr->next)
        npage++;

    rdata = (XLogRecData *) palloc(sizeof(XLogRecData) * (npage * 2 + 2));

    xlrec.node = node;
    xlrec.origblkno = blkno;
    xlrec.origrlink = origrlink;
    xlrec.orignsn = orignsn;
    xlrec.origleaf = page_is_leaf;
    xlrec.npage = (uint16) npage;
    xlrec.leftchild =
        BufferIsValid(leftchildbuf) ? BufferGetBlockNumber(leftchildbuf) : InvalidBlockNumber;
    xlrec.markfollowright = markfollowright;

    rdata[0].data = (char *) &xlrec;
    rdata[0].len = sizeof(gistxlogPageSplit);
    rdata[0].buffer = InvalidBuffer;

    cur = 1;

    /*
     * Include a full page image of the child buf. (only necessary if a
     * checkpoint happened since the child page was split)
     */
    if (BufferIsValid(leftchildbuf))
    {
        rdata[cur - 1].next = &(rdata[cur]);
        rdata[cur].data = NULL;
        rdata[cur].len = 0;
        rdata[cur].buffer = leftchildbuf;
        rdata[cur].buffer_std = true;
        cur++;
    }

    for (ptr = dist; ptr; ptr = ptr->next)
    {
        rdata[cur - 1].next = &(rdata[cur]);
        rdata[cur].buffer = InvalidBuffer;
        rdata[cur].data = (char *) &(ptr->block);
        rdata[cur].len = sizeof(gistxlogPage);
        cur++;

        rdata[cur - 1].next = &(rdata[cur]);
        rdata[cur].buffer = InvalidBuffer;
        rdata[cur].data = (char *) (ptr->list);
        rdata[cur].len = ptr->lenlist;
        cur++;
    }
    rdata[cur - 1].next = NULL;

    recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_PAGE_SPLIT, rdata);

    pfree(rdata);
    return recptr;
}

XLogRecPtr gistXLogUpdate ( RelFileNode  node,
Buffer  buffer,
OffsetNumber todelete,
int  ntodelete,
IndexTuple itup,
int  ituplen,
Buffer  leftchildbuf 
)

Definition at line 460 of file gistxlog.c.

References gistxlogPageUpdate::blkno, XLogRecData::buffer, XLogRecData::buffer_std, BufferGetBlockNumber(), BufferIsValid, cur, XLogRecData::data, i, IndexTupleSize, gistxlogPageUpdate::leftchild, XLogRecData::len, XLogRecData::next, gistxlogPageUpdate::node, gistxlogPageUpdate::ntodelete, palloc(), pfree(), XLOG_GIST_PAGE_UPDATE, and XLogInsert().

Referenced by gistbulkdelete(), and gistplacetopage().

{
    XLogRecData *rdata;
    gistxlogPageUpdate xlrec;
    int         cur,
                i;
    XLogRecPtr  recptr;

    rdata = (XLogRecData *) palloc(sizeof(XLogRecData) * (3 + ituplen));

    xlrec.node = node;
    xlrec.blkno = BufferGetBlockNumber(buffer);
    xlrec.ntodelete = ntodelete;
    xlrec.leftchild =
        BufferIsValid(leftchildbuf) ? BufferGetBlockNumber(leftchildbuf) : InvalidBlockNumber;

    rdata[0].data = (char *) &xlrec;
    rdata[0].len = sizeof(gistxlogPageUpdate);
    rdata[0].buffer = InvalidBuffer;
    rdata[0].next = &(rdata[1]);

    rdata[1].data = (char *) todelete;
    rdata[1].len = sizeof(OffsetNumber) * ntodelete;
    rdata[1].buffer = buffer;
    rdata[1].buffer_std = true;

    cur = 2;

    /* new tuples */
    for (i = 0; i < ituplen; i++)
    {
        rdata[cur - 1].next = &(rdata[cur]);
        rdata[cur].data = (char *) (itup[i]);
        rdata[cur].len = IndexTupleSize(itup[i]);
        rdata[cur].buffer = buffer;
        rdata[cur].buffer_std = true;
        cur++;
    }

    /*
     * Include a full page image of the child buf. (only necessary if a
     * checkpoint happened since the child page was split)
     */
    if (BufferIsValid(leftchildbuf))
    {
        rdata[cur - 1].next = &(rdata[cur]);
        rdata[cur].data = NULL;
        rdata[cur].len = 0;
        rdata[cur].buffer = leftchildbuf;
        rdata[cur].buffer_std = true;
        cur++;
    }
    rdata[cur - 1].next = NULL;

    recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_PAGE_UPDATE, rdata);

    pfree(rdata);
    return recptr;
}


Variable Documentation

MemoryContext opCtx [static]

Definition at line 32 of file gistxlog.c.