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/backend/access/gist/gistutil.c | |
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/backend/access/gist/gistutil.c')
-rw-r--r-- | src/backend/access/gist/gistutil.c | 34 |
1 files changed, 31 insertions, 3 deletions
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c index f32e16eed58..2163cc482d8 100644 --- a/src/backend/access/gist/gistutil.c +++ b/src/backend/access/gist/gistutil.c @@ -23,6 +23,7 @@ #include "storage/lmgr.h" #include "utils/float.h" #include "utils/syscache.h" +#include "utils/snapmgr.h" #include "utils/lsyscache.h" @@ -829,13 +830,31 @@ gistNewBuffer(Relation r) { Page page = BufferGetPage(buffer); + /* + * If the page was never initialized, it's OK to use. + */ if (PageIsNew(page)) - return buffer; /* OK to use, if never initialized */ + return buffer; gistcheckpage(r, buffer); - if (GistPageIsDeleted(page)) - return buffer; /* OK to use */ + /* + * Otherwise, recycle it if deleted, and too old to have any processes + * interested in it. + */ + if (gistPageRecyclable(page)) + { + /* + * If we are generating WAL for Hot Standby then create a + * WAL record that will allow us to conflict with queries + * running on standby, in case they have snapshots older + * than the page's deleteXid. + */ + if (XLogStandbyInfoActive() && RelationNeedsWAL(r)) + gistXLogPageReuse(r, blkno, GistPageGetDeleteXid(page)); + + return buffer; + } LockBuffer(buffer, GIST_UNLOCK); } @@ -859,6 +878,15 @@ gistNewBuffer(Relation r) return buffer; } +/* Can this page be recycled yet? */ +bool +gistPageRecyclable(Page page) +{ + return PageIsNew(page) || + (GistPageIsDeleted(page) && + TransactionIdPrecedes(GistPageGetDeleteXid(page), RecentGlobalXmin)); +} + bytea * gistoptions(Datum reloptions, bool validate) { |