Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 539e92e

Browse files
author
Commitfest Bot
committed
[CF 5542] v12 - Fix buffer pinning logic in [SP-]Gist
This branch was automatically generated by a robot using patches from an email thread registered at: https://commitfest.postgresql.org/patch/5542 The branch will be overwritten each time a new patch version is posted to the thread, and also periodically to check for bitrot caused by changes on the master branch. Patch(es): https://www.postgresql.org/message-id/CAEze2WgnHJF66BtviDFNCPy26gLrb+tfns-Bi62DBfReH0-UCg@mail.gmail.com Author(s): Peter Geoghegan, Michail Nikolaev, Matthias van de Meent, Mihail Nikalayeu
2 parents 6e289f2 + b798aa8 commit 539e92e

28 files changed

+1429
-140
lines changed

src/backend/access/gist/gistget.c

Lines changed: 136 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "access/genam.h"
1818
#include "access/gist_private.h"
1919
#include "access/relscan.h"
20+
#include "access/tableam.h"
2021
#include "lib/pairingheap.h"
2122
#include "miscadmin.h"
2223
#include "pgstat.h"
@@ -394,10 +395,14 @@ gistScanPage(IndexScanDesc scan, GISTSearchItem *pageItem,
394395
return;
395396
}
396397

397-
so->nPageData = so->curPageData = 0;
398+
if (scan->numberOfOrderBys)
399+
so->os.nsortData = 0;
400+
else
401+
so->nos.nPageData = so->nos.curPageData = 0;
402+
398403
scan->xs_hitup = NULL; /* might point into pageDataCxt */
399-
if (so->pageDataCxt)
400-
MemoryContextReset(so->pageDataCxt);
404+
if (so->nos.pageDataCxt)
405+
MemoryContextReset(so->nos.pageDataCxt);
401406

402407
/*
403408
* We save the LSN of the page as we read it, so that we know whether it
@@ -457,22 +462,22 @@ gistScanPage(IndexScanDesc scan, GISTSearchItem *pageItem,
457462
/*
458463
* Non-ordered scan, so report tuples in so->pageData[]
459464
*/
460-
so->pageData[so->nPageData].heapPtr = it->t_tid;
461-
so->pageData[so->nPageData].recheck = recheck;
462-
so->pageData[so->nPageData].offnum = i;
465+
so->nos.pageData[so->nos.nPageData].heapPtr = it->t_tid;
466+
so->nos.pageData[so->nos.nPageData].recheck = recheck;
467+
so->nos.pageData[so->nos.nPageData].offnum = i;
463468

464469
/*
465470
* In an index-only scan, also fetch the data from the tuple. The
466471
* reconstructed tuples are stored in pageDataCxt.
467472
*/
468473
if (scan->xs_want_itup)
469474
{
470-
oldcxt = MemoryContextSwitchTo(so->pageDataCxt);
471-
so->pageData[so->nPageData].recontup =
475+
oldcxt = MemoryContextSwitchTo(so->nos.pageDataCxt);
476+
so->nos.pageData[so->nos.nPageData].recontup =
472477
gistFetchTuple(giststate, r, it);
473478
MemoryContextSwitchTo(oldcxt);
474479
}
475-
so->nPageData++;
480+
so->nos.nPageData++;
476481
}
477482
else
478483
{
@@ -501,7 +506,11 @@ gistScanPage(IndexScanDesc scan, GISTSearchItem *pageItem,
501506
* In an index-only scan, also fetch the data from the tuple.
502507
*/
503508
if (scan->xs_want_itup)
509+
{
504510
item->data.heap.recontup = gistFetchTuple(giststate, r, it);
511+
so->os.sortData[so->os.nsortData] = &item->data.heap;
512+
so->os.nsortData += 1;
513+
}
505514
}
506515
else
507516
{
@@ -526,7 +535,101 @@ gistScanPage(IndexScanDesc scan, GISTSearchItem *pageItem,
526535
}
527536
}
528537

529-
UnlockReleaseBuffer(buffer);
538+
/* Allow writes to the buffer, but don't yet allow VACUUM */
539+
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
540+
541+
/*
542+
* If we're in an index-only scan, we need to do visibility checks before
543+
* we release the pin, so that VACUUM can't clean up dead tuples from this
544+
* index page and mark the page ALL_VISIBLE before the tuple was returned.
545+
*
546+
* See also docs section "Index Locking Considerations".
547+
*/
548+
if (scan->xs_want_itup)
549+
{
550+
TM_IndexVisibilityCheckOp op;
551+
op.vmbuf = &so->vmbuf;
552+
553+
if (scan->numberOfOrderBys > 0)
554+
{
555+
op.checkntids = so->os.nsortData;
556+
557+
if (op.checkntids > 0)
558+
{
559+
op.checktids = palloc(op.checkntids * sizeof(TM_VisCheck));
560+
561+
for (int off = 0; off < op.checkntids; off++)
562+
{
563+
Assert(ItemPointerIsValid(&so->os.sortData[off]->heapPtr));
564+
565+
PopulateTMVischeck(&op.checktids[off],
566+
&so->os.sortData[off]->heapPtr,
567+
off);
568+
}
569+
}
570+
}
571+
else
572+
{
573+
op.checkntids = so->nos.nPageData;
574+
575+
if (op.checkntids > 0)
576+
{
577+
op.checktids = palloc_array(TM_VisCheck, op.checkntids);
578+
579+
for (int off = 0; off < op.checkntids; off++)
580+
{
581+
Assert(ItemPointerIsValid(&so->nos.pageData[off].heapPtr));
582+
583+
PopulateTMVischeck(&op.checktids[off],
584+
&so->nos.pageData[off].heapPtr,
585+
off);
586+
}
587+
}
588+
}
589+
590+
if (op.checkntids > 0)
591+
{
592+
table_index_vischeck_tuples(scan->heapRelation, &op);
593+
594+
if (scan->numberOfOrderBys > 0)
595+
{
596+
for (int off = 0; off < op.checkntids; off++)
597+
{
598+
TM_VisCheck *check = &op.checktids[off];
599+
GISTSearchHeapItem *item = so->os.sortData[check->idxoffnum];
600+
601+
/* sanity checks */
602+
Assert(check->idxoffnum < op.checkntids);
603+
Assert(check->tidblkno == ItemPointerGetBlockNumberNoCheck(&item->heapPtr));
604+
Assert(check->tidoffset == ItemPointerGetOffsetNumberNoCheck(&item->heapPtr));
605+
606+
item->visrecheck = check->vischeckresult;
607+
}
608+
/* reset state */
609+
so->os.nsortData = 0;
610+
}
611+
else
612+
{
613+
for (int off = 0; off < op.checkntids; off++)
614+
{
615+
TM_VisCheck *check = &op.checktids[off];
616+
GISTSearchHeapItem *item = &so->nos.pageData[check->idxoffnum];
617+
618+
Assert(check->idxoffnum < op.checkntids);
619+
Assert(check->tidblkno == ItemPointerGetBlockNumberNoCheck(&item->heapPtr));
620+
Assert(check->tidoffset == ItemPointerGetOffsetNumberNoCheck(&item->heapPtr));
621+
622+
item->visrecheck = check->vischeckresult;
623+
}
624+
}
625+
626+
/* clean up the used resources */
627+
pfree(op.checktids);
628+
}
629+
}
630+
631+
/* Allow VACUUM to process the buffer again */
632+
ReleaseBuffer(buffer);
530633
}
531634

532635
/*
@@ -588,7 +691,10 @@ getNextNearest(IndexScanDesc scan)
588691

589692
/* in an index-only scan, also return the reconstructed tuple. */
590693
if (scan->xs_want_itup)
694+
{
591695
scan->xs_hitup = item->data.heap.recontup;
696+
scan->xs_visrecheck = item->data.heap.visrecheck;
697+
}
592698
res = true;
593699
}
594700
else
@@ -629,10 +735,10 @@ gistgettuple(IndexScanDesc scan, ScanDirection dir)
629735
scan->instrument->nsearches++;
630736

631737
so->firstCall = false;
632-
so->curPageData = so->nPageData = 0;
738+
so->nos.curPageData = so->nos.nPageData = 0;
633739
scan->xs_hitup = NULL;
634-
if (so->pageDataCxt)
635-
MemoryContextReset(so->pageDataCxt);
740+
if (so->nos.pageDataCxt)
741+
MemoryContextReset(so->nos.pageDataCxt);
636742

637743
fakeItem.blkno = GIST_ROOT_BLKNO;
638744
memset(&fakeItem.data.parentlsn, 0, sizeof(GistNSN));
@@ -649,9 +755,9 @@ gistgettuple(IndexScanDesc scan, ScanDirection dir)
649755
/* Fetch tuples index-page-at-a-time */
650756
for (;;)
651757
{
652-
if (so->curPageData < so->nPageData)
758+
if (so->nos.curPageData < so->nos.nPageData)
653759
{
654-
if (scan->kill_prior_tuple && so->curPageData > 0)
760+
if (scan->kill_prior_tuple && so->nos.curPageData > 0)
655761
{
656762

657763
if (so->killedItems == NULL)
@@ -667,17 +773,20 @@ gistgettuple(IndexScanDesc scan, ScanDirection dir)
667773
}
668774
if (so->numKilled < MaxIndexTuplesPerPage)
669775
so->killedItems[so->numKilled++] =
670-
so->pageData[so->curPageData - 1].offnum;
776+
so->nos.pageData[so->nos.curPageData - 1].offnum;
671777
}
672778
/* continuing to return tuples from a leaf page */
673-
scan->xs_heaptid = so->pageData[so->curPageData].heapPtr;
674-
scan->xs_recheck = so->pageData[so->curPageData].recheck;
779+
scan->xs_heaptid = so->nos.pageData[so->nos.curPageData].heapPtr;
780+
scan->xs_recheck = so->nos.pageData[so->nos.curPageData].recheck;
675781

676782
/* in an index-only scan, also return the reconstructed tuple */
677783
if (scan->xs_want_itup)
678-
scan->xs_hitup = so->pageData[so->curPageData].recontup;
784+
{
785+
scan->xs_hitup = so->nos.pageData[so->nos.curPageData].recontup;
786+
scan->xs_visrecheck = so->nos.pageData[so->nos.curPageData].visrecheck;
787+
}
679788

680-
so->curPageData++;
789+
so->nos.curPageData++;
681790

682791
return true;
683792
}
@@ -687,8 +796,8 @@ gistgettuple(IndexScanDesc scan, ScanDirection dir)
687796
* necessary
688797
*/
689798
if (scan->kill_prior_tuple
690-
&& so->curPageData > 0
691-
&& so->curPageData == so->nPageData)
799+
&& so->nos.curPageData > 0
800+
&& so->nos.curPageData == so->nos.nPageData)
692801
{
693802

694803
if (so->killedItems == NULL)
@@ -704,7 +813,7 @@ gistgettuple(IndexScanDesc scan, ScanDirection dir)
704813
}
705814
if (so->numKilled < MaxIndexTuplesPerPage)
706815
so->killedItems[so->numKilled++] =
707-
so->pageData[so->curPageData - 1].offnum;
816+
so->nos.pageData[so->nos.curPageData - 1].offnum;
708817
}
709818
/* find and process the next index page */
710819
do
@@ -733,7 +842,7 @@ gistgettuple(IndexScanDesc scan, ScanDirection dir)
733842
gistScanPage(scan, item, item->distances, NULL, NULL);
734843

735844
pfree(item);
736-
} while (so->nPageData == 0);
845+
} while (so->nos.nPageData == 0);
737846
}
738847
}
739848
}
@@ -756,10 +865,10 @@ gistgetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
756865
scan->instrument->nsearches++;
757866

758867
/* Begin the scan by processing the root page */
759-
so->curPageData = so->nPageData = 0;
868+
so->nos.curPageData = so->nos.nPageData = 0;
760869
scan->xs_hitup = NULL;
761-
if (so->pageDataCxt)
762-
MemoryContextReset(so->pageDataCxt);
870+
if (so->nos.pageDataCxt)
871+
MemoryContextReset(so->nos.pageDataCxt);
763872

764873
fakeItem.blkno = GIST_ROOT_BLKNO;
765874
memset(&fakeItem.data.parentlsn, 0, sizeof(GistNSN));

src/backend/access/gist/gistscan.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -204,9 +204,9 @@ gistrescan(IndexScanDesc scan, ScanKey key, int nkeys,
204204
scan->xs_hitupdesc = so->giststate->fetchTupdesc;
205205

206206
/* Also create a memory context that will hold the returned tuples */
207-
so->pageDataCxt = AllocSetContextCreate(so->giststate->scanCxt,
208-
"GiST page data context",
209-
ALLOCSET_DEFAULT_SIZES);
207+
so->nos.pageDataCxt = AllocSetContextCreate(so->giststate->scanCxt,
208+
"GiST page data context",
209+
ALLOCSET_DEFAULT_SIZES);
210210
}
211211

212212
/* create new, empty pairing heap for search queue */
@@ -347,6 +347,11 @@ void
347347
gistendscan(IndexScanDesc scan)
348348
{
349349
GISTScanOpaque so = (GISTScanOpaque) scan->opaque;
350+
if (BufferIsValid(so->vmbuf))
351+
{
352+
ReleaseBuffer(so->vmbuf);
353+
so->vmbuf = InvalidBuffer;
354+
}
350355

351356
/*
352357
* freeGISTstate is enough to clean up everything made by gistbeginscan,

src/backend/access/gist/gistvacuum.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -326,10 +326,10 @@ gistvacuumpage(GistVacState *vstate, Buffer buffer)
326326
recurse_to = InvalidBlockNumber;
327327

328328
/*
329-
* We are not going to stay here for a long time, aggressively grab an
330-
* exclusive lock.
329+
* We are not going to stay here for a long time, aggressively grab a
330+
* cleanup lock.
331331
*/
332-
LockBuffer(buffer, GIST_EXCLUSIVE);
332+
LockBufferForCleanup(buffer);
333333
page = (Page) BufferGetPage(buffer);
334334

335335
if (gistPageRecyclable(page))

0 commit comments

Comments
 (0)