Re: BUG #18396: Assert in gistFindCorrectParent() fails on inserting large tuples into gist index
Tender Wang <tndrwang@gmail.com>
From: Tender Wang <tndrwang@gmail.com>
To: Heikki Linnakangas <hlinnaka@iki.fi>
Cc: Alexander Lakhin <exclusion@gmail.com>, pgsql-bugs@lists.postgresql.org
Date: 2024-03-26T12:09:12Z
Lists: pgsql-bugs
Heikki Linnakangas <hlinnaka@iki.fi> 于2024年3月19日周二 22:26写道:
> On 19/03/2024 14:07, Tender Wang wrote:
> > Thanks for your report. I can reproduce this issue.
> > I try to delete the Assert, no coredump anymore.
> > I need some time to learn GiST to find the root cause.
> At first glance, I think the assertion is too strict. In
> gistFindCorrectParent(), if we walk right, we update the parent's block
> number and reset its memorized downlinkoffnum to InvalidOffsetNumber. If
> we later call gistFindCorrectParent() again with the same stack, because
> the parent also needs to be split, we hit that assertion. But it's OK in
> that case, we don't know the downlink because we had moved right.
> Attached patch relaxes that.
>
> I tested the code with attached patch many times. No failure anymore.
+1
> But now I'm having some second thoughts. gistFindCorrectParent() looks
> like this:
>
> > /*
> > * Scan the page to re-find the downlink. If the page was split,
> it might
> > * have moved to a different page, so follow the right links until
> we find
> > * it.
> > */
> > while (true)
> > {
> > OffsetNumber i;
> >
> > maxoff = PageGetMaxOffsetNumber(parent->page);
> > for (i = FirstOffsetNumber; i <= maxoff; i =
> OffsetNumberNext(i))
> > {
> > iid = PageGetItemId(parent->page, i);
> > idxtuple = (IndexTuple) PageGetItem(parent->page,
> iid);
> > if (ItemPointerGetBlockNumber(&(idxtuple->t_tid))
> == child->blkno)
> > {
> > /* yes!!, found */
> > child->downlinkoffnum = i;
> > return;
> > }
> > }
> >
> > parent->blkno = GistPageGetOpaque(parent->page)->rightlink;
> > parent->downlinkoffnum = InvalidOffsetNumber;
> > UnlockReleaseBuffer(parent->buffer);
> > if (parent->blkno == InvalidBlockNumber)
> > {
> > /*
> > * End of chain and still didn't find parent. It's
> a very-very
> > * rare situation when the root was split.
> > */
> > break;
> > }
> > parent->buffer = ReadBuffer(r, parent->blkno);
> > LockBuffer(parent->buffer, GIST_EXCLUSIVE);
> > gistcheckpage(r, parent->buffer);
> > parent->page = (Page) BufferGetPage(parent->buffer);
> > }
>
> When we step right and update parent->blkno, shouldn't we also update
> parent->lsn? Otherwise, we might fail to detect a concurrent page split
> with the LSN-NSN interlock checks. Or maybe it's correct, and we should
> indeed not update the memorized LSN. Or maybe it doesn't matter because
> we retry from the parent anyway, thanks to the 'retry_from_parent' flag?
> I'm not sure..
>
I go through the code many times. I found that updating parent->lsn or not
seemd to have no impact. Sorry, I'm not 100% sure.
>
> If you're interested to work on this, Tender, maybe you can figure that
> out?
>
> --
> Heikki Linnakangas
> Neon (https://neon.tech)
>
--
Tender Wang
OpenPie: https://en.openpie.com/
Commits
Same data as JSON:
GET /api/v1/messages/:b64id/commits
the thread's linked commits as JSON, with link sources.
API reference →
-
Relax assertion in finding correct GiST parent
- b92482dc3eff 13.21 landed
- a749c6f18fba 14.18 landed
- 3c0fe75c412b 15.13 landed
- 41932139882e 16.9 landed
- 6526d07948c5 17.5 landed
- 7afca7edef75 18.0 landed
-
Fix another bug in parent page splitting during GiST index build.
- 28d3c2ddcf91 17.0 cited