diff options
author | Heikki Linnakangas <heikki.linnakangas@iki.fi> | 2019-03-22 13:21:20 +0200 |
---|---|---|
committer | Heikki Linnakangas <heikki.linnakangas@iki.fi> | 2019-03-22 13:21:45 +0200 |
commit | 7df159a620b760e289f1795b13542ed1b3e13b87 (patch) | |
tree | e4ca41fc59cf7263e32264791617b9ae5a2dca8e /src/include | |
parent | df816f6ad532ad685a3897869a2e64d3a53fe312 (diff) | |
download | postgresql-7df159a620b760e289f1795b13542ed1b3e13b87.tar.gz postgresql-7df159a620b760e289f1795b13542ed1b3e13b87.zip |
Delete empty pages during GiST VACUUM.
To do this, we scan GiST two times. In the first pass we make note of
empty leaf pages and internal pages. At second pass we scan through
internal pages, looking for downlinks to the empty pages.
Deleting internal pages is still not supported, like in nbtree, the last
child of an internal page is never deleted. That means that if you have a
workload where new keys are always inserted to different area than where
old keys are removed, the index will still grow without bound. But the rate
of growth will be an order of magnitude slower than before.
Author: Andrey Borodin
Discussion: https://www.postgresql.org/message-id/B1E4DF12-6CD3-4706-BDBD-BF3283328F60@yandex-team.ru
Diffstat (limited to 'src/include')
-rw-r--r-- | src/include/access/gist.h | 4 | ||||
-rw-r--r-- | src/include/access/gist_private.h | 11 | ||||
-rw-r--r-- | src/include/access/gistxlog.h | 30 |
3 files changed, 42 insertions, 3 deletions
diff --git a/src/include/access/gist.h b/src/include/access/gist.h index 3234f241560..ce8bfd83ea4 100644 --- a/src/include/access/gist.h +++ b/src/include/access/gist.h @@ -151,6 +151,10 @@ typedef struct GISTENTRY #define GistPageGetNSN(page) ( PageXLogRecPtrGet(GistPageGetOpaque(page)->nsn)) #define GistPageSetNSN(page, val) ( PageXLogRecPtrSet(GistPageGetOpaque(page)->nsn, val)) +/* For deleted pages we store last xid which could see the page in scan */ +#define GistPageGetDeleteXid(page) ( ((PageHeader) (page))->pd_prune_xid ) +#define GistPageSetDeleteXid(page, val) ( ((PageHeader) (page))->pd_prune_xid = val) + /* * Vector of GISTENTRY structs; user-defined methods union and picksplit * take it as one of their arguments diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index 463d2bfc7b9..02dc285a78a 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -414,12 +414,20 @@ 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 XLogRecPtr gistXLogPageDelete(Buffer buffer, + TransactionId xid, Buffer parentBuffer, + OffsetNumber downlinkOffset); + +extern void gistXLogPageReuse(Relation rel, BlockNumber blkno, + TransactionId latestRemovedXid); + extern XLogRecPtr gistXLogUpdate(Buffer buffer, OffsetNumber *todelete, int ntodelete, IndexTuple *itup, int ntup, Buffer leftchild); -XLogRecPtr gistXLogDelete(Buffer buffer, OffsetNumber *todelete, +extern XLogRecPtr gistXLogDelete(Buffer buffer, OffsetNumber *todelete, int ntodelete, RelFileNode hnode); extern XLogRecPtr gistXLogSplit(bool page_is_leaf, @@ -451,6 +459,7 @@ extern bool gistfitpage(IndexTuple *itvec, int len); extern bool gistnospace(Page page, IndexTuple *itvec, int len, OffsetNumber todelete, Size freespace); extern void gistcheckpage(Relation rel, Buffer buf); extern Buffer gistNewBuffer(Relation r); +extern bool gistPageRecyclable(Page page); extern void gistfillbuffer(Page page, IndexTuple *itup, int len, OffsetNumber off); extern IndexTuple *gistextractpage(Page page, int *len /* out */ ); diff --git a/src/include/access/gistxlog.h b/src/include/access/gistxlog.h index 5117aabf1af..2f87b67a53a 100644 --- a/src/include/access/gistxlog.h +++ b/src/include/access/gistxlog.h @@ -19,11 +19,12 @@ #define XLOG_GIST_PAGE_UPDATE 0x00 #define XLOG_GIST_DELETE 0x10 /* delete leaf index tuples for a page */ - /* #define XLOG_GIST_NEW_ROOT 0x20 */ /* not used anymore */ +#define XLOG_GIST_PAGE_REUSE 0x20 /* old page is about to be reused from + * FSM */ #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. @@ -76,6 +77,31 @@ typedef struct gistxlogPageSplit */ } gistxlogPageSplit; +/* + * Backup Blk 0: page that was deleted. + * Backup Blk 1: parent page, containing the downlink to the deleted page. + */ +typedef struct gistxlogPageDelete +{ + TransactionId deleteXid; /* last Xid which could see page in scan */ + OffsetNumber downlinkOffset; /* Offset of downlink referencing this page */ +} gistxlogPageDelete; + +#define SizeOfGistxlogPageDelete (offsetof(gistxlogPageDelete, downlinkOffset) + sizeof(OffsetNumber)) + + +/* + * This is what we need to know about page reuse, for hot standby. + */ +typedef struct gistxlogPageReuse +{ + RelFileNode node; + BlockNumber block; + TransactionId latestRemovedXid; +} gistxlogPageReuse; + +#define SizeOfGistxlogPageReuse (offsetof(gistxlogPageReuse, latestRemovedXid) + sizeof(TransactionId)) + extern void gist_redo(XLogReaderState *record); extern void gist_desc(StringInfo buf, XLogReaderState *record); extern const char *gist_identify(uint8 info); |