Skip to content

Gist vac3 formatting #6

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/backend/access/gist/gist.c
Original file line number Diff line number Diff line change
Expand Up @@ -693,6 +693,13 @@ gistdoinsert(Relation r, IndexTuple itup, Size freespace, GISTSTATE *giststate)
GISTInsertStack *item;
OffsetNumber downlinkoffnum;

if(GistPageIsDeleted(stack->page))
{
UnlockReleaseBuffer(stack->buffer);
xlocked = false;
state.stack = stack = stack->parent;
continue;
}
downlinkoffnum = gistchoose(state.r, stack->page, itup, giststate);
iid = PageGetItemId(stack->page, downlinkoffnum);
idxtuple = (IndexTuple) PageGetItem(stack->page, iid);
Expand Down
5 changes: 0 additions & 5 deletions src/backend/access/gist/gistbuild.c
Original file line number Diff line number Diff line change
Expand Up @@ -1126,11 +1126,6 @@ gistGetMaxLevel(Relation index)
* but will be added there the first time we visit them.
*/

typedef struct
{
BlockNumber childblkno; /* hash key */
BlockNumber parentblkno;
} ParentMapEntry;

static void
gistInitParentMap(GISTBuildState *buildstate)
Expand Down
4 changes: 3 additions & 1 deletion src/backend/access/gist/gistutil.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "storage/lmgr.h"
#include "utils/builtins.h"
#include "utils/syscache.h"
#include "utils/snapmgr.h"


/*
Expand Down Expand Up @@ -801,13 +802,14 @@ gistNewBuffer(Relation r)
if (ConditionalLockBuffer(buffer))
{
Page page = BufferGetPage(buffer);
PageHeader p = (PageHeader) page;

if (PageIsNew(page))
return buffer; /* OK to use, if never initialized */

gistcheckpage(r, buffer);

if (GistPageIsDeleted(page))
if (GistPageIsDeleted(page) && TransactionIdPrecedes(p->pd_prune_xid, RecentGlobalDataXmin))
return buffer; /* OK to use */

LockBuffer(buffer, GIST_UNLOCK);
Expand Down
116 changes: 112 additions & 4 deletions src/backend/access/gist/gistvacuum.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
#include "miscadmin.h"
#include "storage/indexfsm.h"
#include "storage/lmgr.h"
#include "utils/snapmgr.h"
#include "access/xact.h"


/*
Expand Down Expand Up @@ -126,7 +128,6 @@ pushStackIfSplited(Page page, GistBDItem *stack)
}
}


/*
* Bulk deletion of all index entries pointing to a set of heap tuples and
* check invalid tuples left after upgrade.
Expand All @@ -136,12 +137,14 @@ pushStackIfSplited(Page page, GistBDItem *stack)
* Result: a palloc'd struct containing statistical info for VACUUM displays.
*/
IndexBulkDeleteResult *
gistbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
IndexBulkDeleteCallback callback, void *callback_state)
gistbulkdelete(IndexVacuumInfo * info, IndexBulkDeleteResult * stats, IndexBulkDeleteCallback callback, void* callback_state)
{
Relation rel = info->index;
GistBDItem *stack,
*ptr;
BlockNumber recentParent = InvalidBlockNumber;
List *rescanList = NULL;
ListCell *cell;

/* first time through? */
if (stats == NULL)
Expand Down Expand Up @@ -234,9 +237,16 @@ gistbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
END_CRIT_SECTION();
}

if (ntodelete == maxoff && recentParent!=InvalidBlockNumber &&
(rescanList == NULL || (BlockNumber)llast_int(rescanList) != recentParent))
{
/* This page is a candidate to be deleted. Remember it's parent to rescan it later with xlock */
rescanList = lappend_int(rescanList, recentParent);
}
}
else
{
recentParent = stack->blkno;
/* check for split proceeded after look at parent */
pushStackIfSplited(page, stack);

Expand Down Expand Up @@ -271,5 +281,103 @@ gistbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
vacuum_delay_point();
}

/* rescan inner pages that had empty child pages */
foreach(cell,rescanList)
{
Buffer buffer;
Page page;
OffsetNumber i,
maxoff;
IndexTuple idxtuple;
ItemId iid;
OffsetNumber todelete[MaxOffsetNumber];
Buffer buftodelete[MaxOffsetNumber];
int ntodelete = 0;

buffer = ReadBufferExtended(rel, MAIN_FORKNUM, (BlockNumber)lfirst_int(cell),
RBM_NORMAL, info->strategy);
LockBuffer(buffer, GIST_EXCLUSIVE);
gistcheckpage(rel, buffer);
page = (Page) BufferGetPage(buffer);

Assert(!GistPageIsLeaf(page));

maxoff = PageGetMaxOffsetNumber(page);

for (i = OffsetNumberNext(FirstOffsetNumber); i <= maxoff; i = OffsetNumberNext(i))
{
Buffer leafBuffer;
Page leafPage;

iid = PageGetItemId(page, i);
idxtuple = (IndexTuple) PageGetItem(page, iid);

leafBuffer = ReadBufferExtended(rel, MAIN_FORKNUM, ItemPointerGetBlockNumber(&(idxtuple->t_tid)),
RBM_NORMAL, info->strategy);
LockBuffer(leafBuffer, GIST_EXCLUSIVE);
gistcheckpage(rel, leafBuffer);
leafPage = (Page) BufferGetPage(leafBuffer);
Assert(GistPageIsLeaf(leafPage));

if (PageGetMaxOffsetNumber(leafPage) == InvalidOffsetNumber /* Nothing left to split */
&& !(GistFollowRight(leafPage) || GistPageGetNSN(page) < GistPageGetNSN(leafPage)) /* No follow-right */
&& ntodelete < maxoff-1) /* We must keep at leaf one leaf page per each */
{
buftodelete[ntodelete] = leafBuffer;
todelete[ntodelete++] = i;
}
else
UnlockReleaseBuffer(leafBuffer);
}

if (ntodelete)
{
/* Drop references from internal page */
TransactionId txid = GetCurrentTransactionId();
START_CRIT_SECTION();

MarkBufferDirty(buffer);
PageIndexMultiDelete(page, todelete, ntodelete);

if (RelationNeedsWAL(rel))
{
XLogRecPtr recptr;

recptr = gistXLogUpdate(buffer, todelete, ntodelete, NULL, 0, InvalidBuffer);
PageSetLSN(page, recptr);
}
else
PageSetLSN(page, gistGetFakeLSN(rel));

/* Mark pages as deleted */
for (i = 0; i < ntodelete; i++)
{
Page leafPage = (Page)BufferGetPage(buftodelete[i]);
PageHeader header = (PageHeader)leafPage;

header->pd_prune_xid = txid;

GistPageSetDeleted(leafPage);
MarkBufferDirty(buftodelete[i]);
stats->pages_deleted++;

if (RelationNeedsWAL(rel))
{
XLogRecPtr recptr = gistXLogSetDeleted(rel->rd_node, buftodelete[i], header->pd_prune_xid);
PageSetLSN(leafPage, recptr);
}
else
PageSetLSN(leafPage, gistGetFakeLSN(rel));

UnlockReleaseBuffer(buftodelete[i]);
}
END_CRIT_SECTION();
}

UnlockReleaseBuffer(buffer);
}

list_free(rescanList);

return stats;
}
}
47 changes: 45 additions & 2 deletions src/backend/access/gist/gistxlog.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,29 @@ gistRedoClearFollowRight(XLogReaderState *record, uint8 block_id)
UnlockReleaseBuffer(buffer);
}

static void
gistRedoPageSetDeleted(XLogReaderState *record)
{
XLogRecPtr lsn = record->EndRecPtr;
gistxlogPageDelete *xldata = (gistxlogPageDelete *) XLogRecGetData(record);
Buffer buffer;
Page page;
PageHeader header;

if (XLogReadBufferForRedo(record, 0, &buffer) == BLK_NEEDS_REDO)
{
page = (Page) BufferGetPage(buffer);
header = (PageHeader) page;

header->pd_prune_xid = xldata->id;
GistPageSetDeleted(page);

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

UnlockReleaseBuffer(buffer);
}
}
/*
* redo any page update (except page split)
*/
Expand Down Expand Up @@ -112,8 +135,8 @@ gistRedoPageUpdateRecord(XLogReaderState *record)
data += sizeof(OffsetNumber) * xldata->ntodelete;

PageIndexMultiDelete(page, todelete, xldata->ntodelete);
if (GistPageIsLeaf(page))
GistMarkTuplesDeleted(page);

GistMarkTuplesDeleted(page);
}

/* Add new tuples if any */
Expand Down Expand Up @@ -324,6 +347,9 @@ gist_redo(XLogReaderState *record)
case XLOG_GIST_CREATE_INDEX:
gistRedoCreateIndex(record);
break;
case XLOG_GIST_PAGE_DELETE:
gistRedoPageSetDeleted(record);
break;
default:
elog(PANIC, "gist_redo: unknown op code %u", info);
}
Expand Down Expand Up @@ -442,6 +468,23 @@ gistXLogSplit(bool page_is_leaf,
return recptr;
}


XLogRecPtr
gistXLogSetDeleted(RelFileNode node, Buffer buffer, TransactionId xid) {
gistxlogPageDelete xlrec;
XLogRecPtr recptr;

xlrec.id = xid;

XLogBeginInsert();
XLogRegisterData((char *) &xlrec, sizeof(gistxlogPageDelete));

XLogRegisterBuffer(0, buffer, REGBUF_STANDARD);
/* new tuples */
recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_PAGE_DELETE);
return recptr;
}

/*
* Write XLOG record describing a page update. The update can include any
* number of deletions and/or insertions of tuples on a single index page.
Expand Down
23 changes: 16 additions & 7 deletions src/include/access/gist_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

#include "access/amapi.h"
#include "access/gist.h"
#include "access/gistxlog.h"
#include "access/itup.h"
#include "fmgr.h"
#include "lib/pairingheap.h"
Expand Down Expand Up @@ -51,6 +52,11 @@ typedef struct
char tupledata[FLEXIBLE_ARRAY_MEMBER];
} GISTNodeBufferPage;

typedef struct
{
BlockNumber childblkno; /* hash key */
BlockNumber parentblkno;
} ParentMapEntry;
#define BUFFER_PAGE_DATA_OFFSET MAXALIGN(offsetof(GISTNodeBufferPage, tupledata))
/* Returns free space in node buffer page */
#define PAGE_FREE_SPACE(nbp) (nbp->freespace)
Expand Down Expand Up @@ -176,13 +182,6 @@ typedef struct GISTScanOpaqueData

typedef GISTScanOpaqueData *GISTScanOpaque;

/* despite the name, gistxlogPage is not part of any xlog record */
typedef struct gistxlogPage
{
BlockNumber blkno;
int num; /* number of index tuples following */
} gistxlogPage;

/* SplitedPageLayout - gistSplit function result */
typedef struct SplitedPageLayout
{
Expand Down Expand Up @@ -409,6 +408,16 @@ extern bool gistplacetopage(Relation rel, Size freespace, GISTSTATE *giststate,
extern SplitedPageLayout *gistSplit(Relation r, Page page, IndexTuple *itup,
int len, GISTSTATE *giststate);

/* gistxlog.c */
extern void gist_redo(XLogReaderState *record);
extern void gist_desc(StringInfo buf, XLogReaderState *record);
extern const char *gist_identify(uint8 info);
extern void gist_xlog_startup(void);
extern void gist_xlog_cleanup(void);

extern XLogRecPtr gistXLogSetDeleted(RelFileNode node, Buffer buffer,
TransactionId xid);

extern XLogRecPtr gistXLogUpdate(Buffer buffer,
OffsetNumber *todelete, int ntodelete,
IndexTuple *itup, int ntup,
Expand Down
16 changes: 15 additions & 1 deletion src/include/access/gistxlog.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@
#include "access/xlogreader.h"
#include "lib/stringinfo.h"

/* XLog stuff */

#define XLOG_GIST_PAGE_UPDATE 0x00
/* #define XLOG_GIST_NEW_ROOT 0x20 */ /* not used anymore */
#define XLOG_GIST_PAGE_SPLIT 0x30
/* #define XLOG_GIST_INSERT_COMPLETE 0x40 */ /* not used anymore */
#define XLOG_GIST_CREATE_INDEX 0x50
/* #define XLOG_GIST_PAGE_DELETE 0x60 */ /* not used anymore */
#define XLOG_GIST_PAGE_DELETE 0x60

/*
* Backup Blk 0: updated page.
Expand Down Expand Up @@ -59,6 +61,18 @@ typedef struct gistxlogPageSplit
*/
} gistxlogPageSplit;

typedef struct gistxlogPageDelete
{
TransactionId id;
} gistxlogPageDelete;

/* despite the name, gistxlogPage is not part of any xlog record */
typedef struct gistxlogPage
{
BlockNumber blkno;
int num; /* number of index tuples following */
} gistxlogPage;

extern void gist_redo(XLogReaderState *record);
extern void gist_desc(StringInfo buf, XLogReaderState *record);
extern const char *gist_identify(uint8 info);
Expand Down
4 changes: 1 addition & 3 deletions src/test/regress/expected/gist.out
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,7 @@ insert into gist_point_tbl (id, p)
select g+100000, point(g*10+1, g*10+1) from generate_series(1, 10000) g;
-- To test vacuum, delete some entries from all over the index.
delete from gist_point_tbl where id % 2 = 1;
-- And also delete some concentration of values. (GiST doesn't currently
-- attempt to delete pages even when they become empty, but if it did, this
-- would exercise it)
-- And also delete some concentration of values.
delete from gist_point_tbl where id < 10000;
vacuum analyze gist_point_tbl;
-- rebuild the index with a different fillfactor
Expand Down
4 changes: 1 addition & 3 deletions src/test/regress/sql/gist.sql
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,7 @@ select g+100000, point(g*10+1, g*10+1) from generate_series(1, 10000) g;
-- To test vacuum, delete some entries from all over the index.
delete from gist_point_tbl where id % 2 = 1;

-- And also delete some concentration of values. (GiST doesn't currently
-- attempt to delete pages even when they become empty, but if it did, this
-- would exercise it)
-- And also delete some concentration of values.
delete from gist_point_tbl where id < 10000;

vacuum analyze gist_point_tbl;
Expand Down