Skip to content

Commit 6236991

Browse files
committed
Add simple sanity checks on newly-read pages to GiST, too.
1 parent 766dc45 commit 6236991

File tree

5 files changed

+119
-46
lines changed

5 files changed

+119
-46
lines changed

src/backend/access/gist/gist.c

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/access/gist/gist.c,v 1.127 2005/10/18 01:06:22 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/access/gist/gist.c,v 1.128 2005/11/06 22:39:20 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -529,12 +529,12 @@ gistfindleaf(GISTInsertState *state, GISTSTATE *giststate)
529529
* ready to recheck path in a bad case... We remember, that page->lsn
530530
* should never be invalid.
531531
*/
532-
while (true)
532+
for (;;)
533533
{
534-
535534
if (XLogRecPtrIsInvalid(state->stack->lsn))
536535
state->stack->buffer = ReadBuffer(state->r, state->stack->blkno);
537536
LockBuffer(state->stack->buffer, GIST_SHARE);
537+
gistcheckpage(state->r, state->stack->buffer);
538538

539539
state->stack->page = (Page) BufferGetPage(state->stack->buffer);
540540
opaque = GistPageGetOpaque(state->stack->page);
@@ -555,7 +555,6 @@ gistfindleaf(GISTInsertState *state, GISTSTATE *giststate)
555555
continue;
556556
}
557557

558-
559558
if (!GistPageIsLeaf(state->stack->page))
560559
{
561560
/*
@@ -649,14 +648,18 @@ gistReadAndLockBuffer(Relation r, BlockNumber blkno)
649648
}
650649

651650
/*
652-
* Traverse the tree to find path from root page,
653-
* to prevent deadlocks, it should lock only one page simultaneously.
654-
* Function uses in recovery and usial mode, so should work with different
655-
* read functions (gistReadAndLockBuffer and XLogReadBuffer)
651+
* Traverse the tree to find path from root page.
652+
*
656653
* returns from the begining of closest parent;
654+
*
655+
* Function is used in both regular and recovery mode, so must work with
656+
* different read functions (gistReadAndLockBuffer and XLogReadBuffer)
657+
*
658+
* To prevent deadlocks, this should lock only one page simultaneously.
657659
*/
658660
GISTInsertStack *
659-
gistFindPath(Relation r, BlockNumber child, Buffer (*myReadBuffer) (Relation, BlockNumber))
661+
gistFindPath(Relation r, BlockNumber child,
662+
Buffer (*myReadBuffer) (Relation, BlockNumber))
660663
{
661664
Page page;
662665
Buffer buffer;
@@ -674,7 +677,8 @@ gistFindPath(Relation r, BlockNumber child, Buffer (*myReadBuffer) (Relation, Bl
674677

675678
while (top && top->blkno != child)
676679
{
677-
buffer = myReadBuffer(r, top->blkno); /* buffer locked */
680+
buffer = myReadBuffer(r, top->blkno); /* locks buffer */
681+
gistcheckpage(r, buffer);
678682
page = (Page) BufferGetPage(buffer);
679683

680684
if (GistPageIsLeaf(page))
@@ -771,9 +775,9 @@ gistFindCorrectParent(Relation r, GISTInsertStack *child)
771775
GISTInsertStack *parent = child->parent;
772776

773777
LockBuffer(parent->buffer, GIST_EXCLUSIVE);
778+
gistcheckpage(r, parent->buffer);
774779
parent->page = (Page) BufferGetPage(parent->buffer);
775780

776-
777781
/* here we don't need to distinguish between split and page update */
778782
if (parent->childoffnum == InvalidOffsetNumber || !XLByteEQ(parent->lsn, PageGetLSN(parent->page)))
779783
{
@@ -811,6 +815,7 @@ gistFindCorrectParent(Relation r, GISTInsertStack *child)
811815
break;
812816
parent->buffer = ReadBuffer(r, parent->blkno);
813817
LockBuffer(parent->buffer, GIST_EXCLUSIVE);
818+
gistcheckpage(r, parent->buffer);
814819
parent->page = (Page) BufferGetPage(parent->buffer);
815820
}
816821

@@ -831,7 +836,8 @@ gistFindCorrectParent(Relation r, GISTInsertStack *child)
831836
ptr = parent = gistFindPath(r, child->blkno, gistReadAndLockBuffer);
832837
Assert(ptr != NULL);
833838

834-
/* read all buffers as supposed in caller */
839+
/* read all buffers as expected by caller */
840+
/* note we don't lock them or gistcheckpage them here! */
835841
while (ptr)
836842
{
837843
ptr->buffer = ReadBuffer(r, ptr->blkno);

src/backend/access/gist/gistget.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/access/gist/gistget.c,v 1.52 2005/10/06 02:29:07 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/access/gist/gistget.c,v 1.53 2005/11/06 22:39:20 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -40,6 +40,7 @@ killtuple(Relation r, GISTScanOpaque so, ItemPointer iptr)
4040
maxoff;
4141

4242
LockBuffer(buffer, GIST_SHARE);
43+
gistcheckpage(r, buffer);
4344
p = (Page) BufferGetPage(buffer);
4445

4546
if (buffer == so->curbuf && XLByteEQ(so->stack->lsn, PageGetLSN(p)))
@@ -176,6 +177,7 @@ gistnext(IndexScanDesc scan, ScanDirection dir, ItemPointer tids, int maxtids, b
176177
/* First of all, we need lock buffer */
177178
Assert(so->curbuf != InvalidBuffer);
178179
LockBuffer(so->curbuf, GIST_SHARE);
180+
gistcheckpage(scan->indexRelation, so->curbuf);
179181
p = BufferGetPage(so->curbuf);
180182
opaque = GistPageGetOpaque(p);
181183
resetoffset = false;
@@ -224,7 +226,8 @@ gistnext(IndexScanDesc scan, ScanDirection dir, ItemPointer tids, int maxtids, b
224226
continue;
225227
}
226228

227-
if (!GistPageIsLeaf(p) || resetoffset || ItemPointerIsValid(&scan->currentItemData) == false)
229+
if (!GistPageIsLeaf(p) || resetoffset ||
230+
!ItemPointerIsValid(&scan->currentItemData))
228231
{
229232
if (ScanDirectionIsBackward(dir))
230233
n = PageGetMaxOffsetNumber(p);
@@ -268,7 +271,8 @@ gistnext(IndexScanDesc scan, ScanDirection dir, ItemPointer tids, int maxtids, b
268271
return ntids;
269272
}
270273

271-
so->curbuf = ReleaseAndReadBuffer(so->curbuf, scan->indexRelation,
274+
so->curbuf = ReleaseAndReadBuffer(so->curbuf,
275+
scan->indexRelation,
272276
stk->block);
273277
/* XXX go up */
274278
break;

src/backend/access/gist/gistutil.c

Lines changed: 82 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/access/gist/gistutil.c,v 1.7 2005/09/22 20:44:36 momjian Exp $
11+
* $PostgreSQL: pgsql/src/backend/access/gist/gistutil.c,v 1.8 2005/11/06 22:39:20 tgl Exp $
1212
*-------------------------------------------------------------------------
1313
*/
1414
#include "postgres.h"
@@ -798,23 +798,6 @@ gistpenalty(GISTSTATE *giststate, int attno,
798798
PointerGetDatum(penalty));
799799
}
800800

801-
void
802-
GISTInitBuffer(Buffer b, uint32 f)
803-
{
804-
GISTPageOpaque opaque;
805-
Page page;
806-
Size pageSize;
807-
808-
pageSize = BufferGetPageSize(b);
809-
page = BufferGetPage(b);
810-
PageInit(page, pageSize, sizeof(GISTPageOpaqueData));
811-
812-
opaque = GistPageGetOpaque(page);
813-
opaque->flags = f;
814-
opaque->rightlink = InvalidBlockNumber;
815-
memset(&(opaque->nsn), 0, sizeof(GistNSN));
816-
}
817-
818801
void
819802
gistUserPicksplit(Relation r, GistEntryVector *entryvec, GIST_SPLITVEC *v,
820803
IndexTuple *itup, int len, GISTSTATE *giststate)
@@ -864,36 +847,108 @@ gistUserPicksplit(Relation r, GistEntryVector *entryvec, GIST_SPLITVEC *v,
864847
}
865848
}
866849

850+
/*
851+
* Initialize a new index page
852+
*/
853+
void
854+
GISTInitBuffer(Buffer b, uint32 f)
855+
{
856+
GISTPageOpaque opaque;
857+
Page page;
858+
Size pageSize;
859+
860+
pageSize = BufferGetPageSize(b);
861+
page = BufferGetPage(b);
862+
PageInit(page, pageSize, sizeof(GISTPageOpaqueData));
863+
864+
opaque = GistPageGetOpaque(page);
865+
opaque->flags = f;
866+
opaque->rightlink = InvalidBlockNumber;
867+
/* page was already zeroed by PageInit, so this is not needed: */
868+
/* memset(&(opaque->nsn), 0, sizeof(GistNSN)); */
869+
}
870+
871+
/*
872+
* Verify that a freshly-read page looks sane.
873+
*/
874+
void
875+
gistcheckpage(Relation rel, Buffer buf)
876+
{
877+
Page page = BufferGetPage(buf);
878+
879+
/*
880+
* ReadBuffer verifies that every newly-read page passes PageHeaderIsValid,
881+
* which means it either contains a reasonably sane page header or is
882+
* all-zero. We have to defend against the all-zero case, however.
883+
*/
884+
if (PageIsNew(page))
885+
ereport(ERROR,
886+
(errcode(ERRCODE_INDEX_CORRUPTED),
887+
errmsg("index \"%s\" contains unexpected zero page at block %u",
888+
RelationGetRelationName(rel),
889+
BufferGetBlockNumber(buf)),
890+
errhint("Please REINDEX it.")));
891+
892+
/*
893+
* Additionally check that the special area looks sane.
894+
*/
895+
if (((PageHeader) (page))->pd_special !=
896+
(BLCKSZ - MAXALIGN(sizeof(GISTPageOpaqueData))))
897+
ereport(ERROR,
898+
(errcode(ERRCODE_INDEX_CORRUPTED),
899+
errmsg("index \"%s\" contains corrupted page at block %u",
900+
RelationGetRelationName(rel),
901+
BufferGetBlockNumber(buf)),
902+
errhint("Please REINDEX it.")));
903+
}
904+
905+
906+
/*
907+
* Allocate a new page (either by recycling, or by extending the index file)
908+
*
909+
* The returned buffer is already pinned and exclusive-locked
910+
*
911+
* Caller is responsible for initializing the page by calling GISTInitBuffer
912+
*/
867913
Buffer
868914
gistNewBuffer(Relation r)
869915
{
870-
Buffer buffer = InvalidBuffer;
916+
Buffer buffer;
871917
bool needLock;
872918

873-
while (true)
919+
/* First, try to get a page from FSM */
920+
for (;;)
874921
{
875922
BlockNumber blkno = GetFreeIndexPage(&r->rd_node);
876923

877924
if (blkno == InvalidBlockNumber)
878-
break;
925+
break; /* nothing left in FSM */
879926

880927
buffer = ReadBuffer(r, blkno);
928+
/*
929+
* We have to guard against the possibility that someone else already
930+
* recycled this page; the buffer may be locked if so.
931+
*/
881932
if (ConditionalLockBuffer(buffer))
882933
{
883934
Page page = BufferGetPage(buffer);
884935

936+
if (PageIsNew(page))
937+
return buffer; /* OK to use, if never initialized */
938+
939+
gistcheckpage(r, buffer);
940+
885941
if (GistPageIsDeleted(page))
886-
{
887-
GistPageSetNonDeleted(page);
888-
return buffer;
889-
}
890-
else
891-
LockBuffer(buffer, GIST_UNLOCK);
942+
return buffer; /* OK to use */
943+
944+
LockBuffer(buffer, GIST_UNLOCK);
892945
}
893946

947+
/* Can't use it, so release buffer and try again */
894948
ReleaseBuffer(buffer);
895949
}
896950

951+
/* Must extend the file */
897952
needLock = !RELATION_IS_LOCAL(r);
898953

899954
if (needLock)

src/backend/access/gist/gistvacuum.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/access/gist/gistvacuum.c,v 1.9 2005/09/22 20:44:36 momjian Exp $
11+
* $PostgreSQL: pgsql/src/backend/access/gist/gistvacuum.c,v 1.10 2005/11/06 22:39:20 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -65,6 +65,11 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
6565
lencompleted = 16;
6666

6767
buffer = ReadBuffer(gv->index, blkno);
68+
/*
69+
* This is only used during VACUUM FULL, so we need not bother to lock
70+
* individual index pages
71+
*/
72+
gistcheckpage(gv->index, buffer);
6873
page = (Page) BufferGetPage(buffer);
6974
maxoff = PageGetMaxOffsetNumber(page);
7075

@@ -378,9 +383,10 @@ gistvacuumcleanup(PG_FUNCTION_ARGS)
378383

379384
needFullVacuum = false;
380385

381-
needLock = !RELATION_IS_LOCAL(rel);
382386
if (info->vacuum_full)
383387
needLock = false; /* relation locked with AccessExclusiveLock */
388+
else
389+
needLock = !RELATION_IS_LOCAL(rel);
384390

385391
/* try to find deleted pages */
386392
if (needLock)
@@ -403,7 +409,7 @@ gistvacuumcleanup(PG_FUNCTION_ARGS)
403409
LockBuffer(buffer, GIST_SHARE);
404410
page = (Page) BufferGetPage(buffer);
405411

406-
if (GistPageIsDeleted(page))
412+
if (PageIsNew(page) || GistPageIsDeleted(page))
407413
{
408414
if (nFreePages < maxFreePages)
409415
{
@@ -513,6 +519,7 @@ gistbulkdelete(PG_FUNCTION_ARGS)
513519
ItemId iid;
514520

515521
LockBuffer(buffer, GIST_SHARE);
522+
gistcheckpage(rel, buffer);
516523
page = (Page) BufferGetPage(buffer);
517524

518525
if (GistPageIsLeaf(page))

src/include/access/gist_private.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/access/gist_private.h,v 1.8 2005/10/15 02:49:42 momjian Exp $
10+
* $PostgreSQL: pgsql/src/include/access/gist_private.h,v 1.9 2005/11/06 22:39:21 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -263,6 +263,7 @@ extern Datum gistgettuple(PG_FUNCTION_ARGS);
263263
extern Datum gistgetmulti(PG_FUNCTION_ARGS);
264264

265265
/* gistutil.c */
266+
extern void gistcheckpage(Relation rel, Buffer buf);
266267
extern Buffer gistNewBuffer(Relation r);
267268
extern OffsetNumber gistfillbuffer(Relation r, Page page, IndexTuple *itup,
268269
int len, OffsetNumber off);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy