Re: GiST VACUUM
Heikki Linnakangas <hlinnaka@iki.fi>
From: Heikki Linnakangas <hlinnaka@iki.fi>
To: Andrey Borodin <x4mmm@yandex-team.ru>,
Thomas Munro <thomas.munro@enterprisedb.com>
Cc: pgsql-hackers <pgsql-hackers@postgresql.org>, Костя Кузнецов <chapaev28@ya.ru>
Date: 2018-07-10T20:07:44Z
Lists: pgsql-hackers
I'm now looking at the first patch in this series, to allow completely
empty GiST pages to be recycled. I've got some questions:
> --- a/src/backend/access/gist/gist.c
> +++ b/src/backend/access/gist/gist.c
> @@ -700,6 +700,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);
This seems misplaced. This code deals with internal pages, and as far as
I can see, this patch never marks internal pages as deleted, only leaf
pages. However, we should have something like this in the leaf-page
branch, to deal with the case that an insertion lands on a page that was
concurrently deleted. Did you have any tests, where an insertion runs
concurrently with vacuum, that would exercise this?
The code in gistbulkdelete() seems pretty expensive. In the first phase,
it records the parent of every empty leaf page it encounters. In the
second phase, it scans every leaf page of that parent, not only those
leaves that were seen as empty.
I'm a bit wary of using pd_prune_xid for the checks to determine if a
deleted page can be recycled yet. In heap pages, pd_prune_xid is just a
hint, but here it's used for a critical check. This seems to be the same
mechanism we use in B-trees, but in B-trees, we store the XID in
BTPageOpaqueData.xact, not pd_prune_xid. Also, in B-trees, we use
ReadNewTransactionId() to set it, not GetCurrentTransactionId(). See
comments in _bt_unlink_halfdead_page() for explanation. This patch is
missing any comments to explain how this works in GiST.
If you crash in the middle of gistbulkdelete(), after it has removed the
downlink from the parent, but before it has marked the leaf page as
deleted, the leaf page is "leaked". I think that's acceptable, but a
comment at least would be good.
- Heikki
Commits
-
Use full 64-bit XID for checking if a deleted GiST page is old enough.
- fb5344c969af 12.0 landed
- 6655a7299d83 13.0 landed
-
Refactor checks for deleted GiST pages.
- e2e992c93145 12.0 landed
- 9eb5607e6993 13.0 landed
-
Delete empty pages during GiST VACUUM.
- 7df159a620b7 12.0 landed
-
Scan GiST indexes in physical order during VACUUM.
- fe280694d0d4 12.0 landed
-
Prevent GIN deleted pages from being reclaimed too early
- 52ac6cd2d0cd 12.0 cited