Skip to content

Commit 898a7bd

Browse files
committed
Bug fixes for GiST crash recovery.
- add forgotten check of lsn for insert completion - remove level of pages: hard to check in recovery - some cleanups
1 parent 7a30b1f commit 898a7bd

File tree

6 files changed

+95
-65
lines changed

6 files changed

+95
-65
lines changed

src/backend/access/gist/gist.c

Lines changed: 12 additions & 13 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.124 2005/06/29 14:06:14 teodor Exp $
11+
* $PostgreSQL: pgsql/src/backend/access/gist/gist.c,v 1.125 2005/06/30 17:52:13 teodor Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -587,7 +587,7 @@ gistfindleaf(GISTInsertState *state, GISTSTATE *giststate)
587587
* Should have the same interface as XLogReadBuffer
588588
*/
589589
static Buffer
590-
gistReadAndLockBuffer( bool unused, Relation r, BlockNumber blkno ) {
590+
gistReadAndLockBuffer( Relation r, BlockNumber blkno ) {
591591
Buffer buffer = ReadBuffer( r, blkno );
592592
LockBuffer( buffer, GIST_SHARE );
593593
return buffer;
@@ -601,7 +601,7 @@ gistReadAndLockBuffer( bool unused, Relation r, BlockNumber blkno ) {
601601
* returns from the begining of closest parent;
602602
*/
603603
GISTInsertStack*
604-
gistFindPath( Relation r, BlockNumber child, Buffer (*myReadBuffer)(bool, Relation, BlockNumber) ) {
604+
gistFindPath( Relation r, BlockNumber child, Buffer (*myReadBuffer)(Relation, BlockNumber) ) {
605605
Page page;
606606
Buffer buffer;
607607
OffsetNumber i, maxoff;
@@ -614,9 +614,15 @@ gistFindPath( Relation r, BlockNumber child, Buffer (*myReadBuffer)(bool, Relat
614614
top->blkno = GIST_ROOT_BLKNO;
615615

616616
while( top && top->blkno != child ) {
617-
buffer = myReadBuffer(false, r, top->blkno); /* buffer locked */
617+
buffer = myReadBuffer(r, top->blkno); /* buffer locked */
618618
page = (Page)BufferGetPage( buffer );
619-
Assert( !GistPageIsLeaf(page) );
619+
620+
if ( GistPageIsLeaf(page) ) {
621+
/* we can safety go away, follows only leaf pages */
622+
LockBuffer( buffer, GIST_UNLOCK );
623+
ReleaseBuffer( buffer );
624+
return NULL;
625+
}
620626

621627
top->lsn = PageGetLSN(page);
622628

@@ -662,7 +668,7 @@ gistFindPath( Relation r, BlockNumber child, Buffer (*myReadBuffer)(bool, Relat
662668
LockBuffer( buffer, GIST_UNLOCK );
663669
ReleaseBuffer( buffer );
664670
return top;
665-
} else if ( GistPageGetOpaque(page)->level> 0 ) {
671+
} else {
666672
/* Install next inner page to the end of stack */
667673
ptr = (GISTInsertStack*)palloc0( sizeof(GISTInsertStack) );
668674
ptr->blkno = blkno;
@@ -855,11 +861,9 @@ gistSplit(Relation r,
855861
OffsetNumber *realoffset;
856862
IndexTuple *cleaneditup = itup;
857863
int lencleaneditup = *len;
858-
int level;
859864

860865
p = (Page) BufferGetPage(buffer);
861866
opaque = GistPageGetOpaque(p);
862-
level = opaque->level;
863867

864868
/*
865869
* The root of the tree is the first block in the relation. If we're
@@ -872,7 +876,6 @@ gistSplit(Relation r,
872876
GISTInitBuffer(leftbuf, opaque->flags&F_LEAF);
873877
lbknum = BufferGetBlockNumber(leftbuf);
874878
left = (Page) BufferGetPage(leftbuf);
875-
GistPageGetOpaque(left)->level = level;
876879
}
877880
else
878881
{
@@ -886,7 +889,6 @@ gistSplit(Relation r,
886889
GISTInitBuffer(rightbuf, opaque->flags&F_LEAF);
887890
rbknum = BufferGetBlockNumber(rightbuf);
888891
right = (Page) BufferGetPage(rightbuf);
889-
GistPageGetOpaque(right)->level = level;
890892

891893
/* generate the item array */
892894
realoffset = palloc((*len + 1) * sizeof(OffsetNumber));
@@ -1068,13 +1070,10 @@ void
10681070
gistnewroot(Relation r, Buffer buffer, IndexTuple *itup, int len, ItemPointer key)
10691071
{
10701072
Page page;
1071-
int level;
10721073

10731074
Assert( BufferGetBlockNumber(buffer) == GIST_ROOT_BLKNO );
10741075
page = BufferGetPage(buffer);
1075-
level = GistPageGetOpaque(page)->level;
10761076
GISTInitBuffer(buffer, 0);
1077-
GistPageGetOpaque(page)->level = level+1;
10781077

10791078
gistfillbuffer(r, page, itup, len, FirstOffsetNumber);
10801079
if ( !r->rd_istemp ) {

src/backend/access/gist/gistutil.c

Lines changed: 1 addition & 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/gistutil.c,v 1.4 2005/06/28 15:51:00 teodor Exp $
11+
* $PostgreSQL: pgsql/src/backend/access/gist/gistutil.c,v 1.5 2005/06/30 17:52:14 teodor Exp $
1212
*-------------------------------------------------------------------------
1313
*/
1414
#include "postgres.h"
@@ -809,8 +809,6 @@ GISTInitBuffer(Buffer b, uint32 f)
809809

810810
opaque = GistPageGetOpaque(page);
811811
opaque->flags = f;
812-
opaque->nsplited = 0;
813-
opaque->level = 0;
814812
opaque->rightlink = InvalidBlockNumber;
815813
memset( &(opaque->nsn), 0, sizeof(GistNSN) );
816814
}

src/backend/access/gist/gistvacuum.c

Lines changed: 1 addition & 2 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.5 2005/06/29 14:06:14 teodor Exp $
11+
* $PostgreSQL: pgsql/src/backend/access/gist/gistvacuum.c,v 1.6 2005/06/30 17:52:14 teodor Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -60,7 +60,6 @@ gistVacuumUpdate( GistVacuum *gv, BlockNumber blkno, bool needunion ) {
6060
page = (Page) BufferGetPage(buffer);
6161
maxoff = PageGetMaxOffsetNumber(page);
6262

63-
6463
if ( GistPageIsLeaf(page) ) {
6564
if ( GistTuplesDeleted(page) ) {
6665
needunion = needwrite = true;

src/backend/access/gist/gistxlog.c

Lines changed: 77 additions & 37 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/gistxlog.c,v 1.5 2005/06/28 15:51:00 teodor Exp $
11+
* $PostgreSQL: pgsql/src/backend/access/gist/gistxlog.c,v 1.6 2005/06/30 17:52:14 teodor Exp $
1212
*-------------------------------------------------------------------------
1313
*/
1414
#include "postgres.h"
@@ -44,6 +44,7 @@ typedef struct {
4444

4545
typedef struct gistIncompleteInsert {
4646
RelFileNode node;
47+
BlockNumber origblkno; /* for splits */
4748
ItemPointerData key;
4849
int lenblk;
4950
BlockNumber *blkno;
@@ -79,6 +80,7 @@ pushIncompleteInsert(RelFileNode node, XLogRecPtr lsn, ItemPointerData key,
7980
ninsert->lenblk = lenblk;
8081
ninsert->blkno = (BlockNumber*)palloc( sizeof(BlockNumber)*ninsert->lenblk );
8182
memcpy(ninsert->blkno, blkno, sizeof(BlockNumber)*ninsert->lenblk);
83+
ninsert->origblkno = *blkno;
8284
} else {
8385
int i;
8486

@@ -87,6 +89,7 @@ pushIncompleteInsert(RelFileNode node, XLogRecPtr lsn, ItemPointerData key,
8789
ninsert->blkno = (BlockNumber*)palloc( sizeof(BlockNumber)*ninsert->lenblk );
8890
for(i=0;i<ninsert->lenblk;i++)
8991
ninsert->blkno[i] = xlinfo->page[i].header->blkno;
92+
ninsert->origblkno = xlinfo->data->origblkno;
9093
}
9194
Assert( ninsert->lenblk>0 );
9295

@@ -209,6 +212,7 @@ gistRedoEntryUpdateRecord(XLogRecPtr lsn, XLogRecord *record, bool isnewroot) {
209212

210213
PageSetLSN(page, lsn);
211214
PageSetTLI(page, ThisTimeLineID);
215+
GistPageGetOpaque(page)->rightlink = InvalidBlockNumber;
212216
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
213217
WriteBuffer(buffer);
214218

@@ -466,81 +470,98 @@ gist_form_invalid_tuple(BlockNumber blkno) {
466470
return tuple;
467471
}
468472

473+
static Buffer
474+
gistXLogReadAndLockBuffer( Relation r, BlockNumber blkno ) {
475+
Buffer buffer = XLogReadBuffer( false, r, blkno );
476+
if (!BufferIsValid(buffer))
477+
elog(PANIC, "gistXLogReadAndLockBuffer: block %u unfound", blkno);
478+
if ( PageIsNew( (PageHeader)(BufferGetPage(buffer)) ) )
479+
elog(PANIC, "gistXLogReadAndLockBuffer: uninitialized page %u", blkno);
480+
481+
return buffer;
482+
}
483+
484+
469485
static void
470486
gixtxlogFindPath( Relation index, gistIncompleteInsert *insert ) {
471-
int i;
472487
GISTInsertStack *top;
473488

474489
insert->pathlen = 0;
475490
insert->path = NULL;
476491

477-
for(i=0;insert->lenblk;i++) {
478-
if ( (top=gistFindPath(index, insert->blkno[i], XLogReadBuffer)) != NULL ) {
479-
GISTInsertStack *ptr=top;
480-
while(ptr) {
481-
insert->pathlen++;
482-
ptr = ptr->parent;
483-
}
492+
if ( (top=gistFindPath(index, insert->origblkno, gistXLogReadAndLockBuffer)) != NULL ) {
493+
int i;
494+
GISTInsertStack *ptr=top;
495+
while(ptr) {
496+
insert->pathlen++;
497+
ptr = ptr->parent;
498+
}
484499

485-
insert->path=(BlockNumber*)palloc( sizeof(BlockNumber) * insert->pathlen );
500+
insert->path=(BlockNumber*)palloc( sizeof(BlockNumber) * insert->pathlen );
486501

487-
i=0;
488-
ptr = top;
489-
while(ptr) {
490-
insert->path[i] = ptr->blkno;
491-
i++;
492-
ptr = ptr->parent;
493-
}
494-
break;
502+
i=0;
503+
ptr = top;
504+
while(ptr) {
505+
insert->path[i] = ptr->blkno;
506+
i++;
507+
ptr = ptr->parent;
495508
}
496-
}
509+
} else
510+
elog(LOG, "gixtxlogFindPath: lost parent for block %u", insert->origblkno);
497511
}
498512

499513
static void
500514
gistContinueInsert(gistIncompleteInsert *insert) {
501515
IndexTuple *itup;
502516
int i, lenitup;
503-
MemoryContext oldCxt;
504517
Relation index;
505518

506-
oldCxt = MemoryContextSwitchTo(opCtx);
507-
508519
index = XLogOpenRelation(insert->node);
509-
if (!RelationIsValid(index))
520+
if (!RelationIsValid(index))
510521
return;
511522

512-
elog(LOG,"Detected incomplete insert into GiST index %u/%u/%u; It's desirable to vacuum or reindex index",
513-
insert->node.spcNode, insert->node.dbNode, insert->node.relNode);
514-
515523
/* needed vector itup never will be more than initial lenblkno+2,
516524
because during this processing Indextuple can be only smaller */
517525
lenitup = insert->lenblk;
518526
itup = (IndexTuple*)palloc(sizeof(IndexTuple)*(lenitup+2 /*guarantee root split*/));
519527

520-
for(i=0;i<insert->lenblk;i++)
528+
for(i=0;i<insert->lenblk;i++)
521529
itup[i] = gist_form_invalid_tuple( insert->blkno[i] );
522530

523-
/* construct path */
524-
gixtxlogFindPath( index, insert );
525-
526-
if ( insert->pathlen==0 ) {
527-
/*it was split root, so we should only make new root*/
531+
if ( insert->origblkno==GIST_ROOT_BLKNO ) {
532+
/*it was split root, so we should only make new root.
533+
it can't be simple insert into root, look at call
534+
pushIncompleteInsert in gistRedoPageSplitRecord */
528535
Buffer buffer = XLogReadBuffer(true, index, GIST_ROOT_BLKNO);
529536
Page page;
530537

531538
if (!BufferIsValid(buffer))
532539
elog(PANIC, "gistContinueInsert: root block unfound");
533540

541+
page = BufferGetPage(buffer);
542+
if (XLByteLE(insert->lsn, PageGetLSN(page))) {
543+
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
544+
ReleaseBuffer(buffer);
545+
return;
546+
}
547+
534548
GISTInitBuffer(buffer, 0);
535549
page = BufferGetPage(buffer);
536550
gistfillbuffer(index, page, itup, lenitup, FirstOffsetNumber);
551+
PageSetLSN(page, insert->lsn);
552+
PageSetTLI(page, ThisTimeLineID);
537553
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
538554
WriteBuffer(buffer);
539555
} else {
540556
Buffer *buffers;
541557
Page *pages;
542558
int numbuffer;
543-
559+
560+
/* construct path */
561+
gixtxlogFindPath( index, insert );
562+
563+
Assert( insert->pathlen > 0 );
564+
544565
buffers= (Buffer*) palloc( sizeof(Buffer) * (insert->lenblk+2/*guarantee root split*/) );
545566
pages = (Page*) palloc( sizeof(Page ) * (insert->lenblk+2/*guarantee root split*/) );
546567

@@ -555,6 +576,12 @@ gistContinueInsert(gistIncompleteInsert *insert) {
555576
if ( PageIsNew((PageHeader)(pages[numbuffer-1])) )
556577
elog(PANIC, "gistContinueInsert: uninitialized page");
557578

579+
if (XLByteLE(insert->lsn, PageGetLSN(pages[numbuffer-1]))) {
580+
LockBuffer(buffers[numbuffer-1], BUFFER_LOCK_UNLOCK);
581+
ReleaseBuffer(buffers[numbuffer-1]);
582+
return;
583+
}
584+
558585
pituplen = PageGetMaxOffsetNumber(pages[numbuffer-1]);
559586

560587
/* remove old IndexTuples */
@@ -587,9 +614,10 @@ gistContinueInsert(gistIncompleteInsert *insert) {
587614
if ( BufferGetBlockNumber( buffers[0] ) == GIST_ROOT_BLKNO ) {
588615
IndexTuple *parentitup;
589616

617+
/* we split root, just copy tuples from old root to new page */
590618
parentitup = gistextractbuffer(buffers[numbuffer-1], &pituplen);
591619

592-
/* we split root, just copy tuples from old root to new page */
620+
/* sanity check */
593621
if ( i+1 != insert->pathlen )
594622
elog(PANIC,"gistContinueInsert: can't restore index '%s'",
595623
RelationGetRelationName( index ));
@@ -624,14 +652,15 @@ gistContinueInsert(gistIncompleteInsert *insert) {
624652
itup[j]=gist_form_invalid_tuple( BufferGetBlockNumber( buffers[j] ) );
625653
PageSetLSN(pages[j], insert->lsn);
626654
PageSetTLI(pages[j], ThisTimeLineID);
655+
GistPageGetOpaque(pages[j])->rightlink = InvalidBlockNumber;
627656
LockBuffer(buffers[j], BUFFER_LOCK_UNLOCK);
628657
WriteBuffer( buffers[j] );
629658
}
630659
}
631660
}
632661

633-
MemoryContextSwitchTo(oldCxt);
634-
MemoryContextReset(opCtx);
662+
elog(LOG,"Detected incomplete insert into GiST index %u/%u/%u; It's desirable to vacuum or reindex index",
663+
insert->node.spcNode, insert->node.dbNode, insert->node.relNode);
635664
}
636665

637666
void
@@ -648,11 +677,22 @@ gist_xlog_startup(void) {
648677
void
649678
gist_xlog_cleanup(void) {
650679
ListCell *l;
680+
List *reverse=NIL;
681+
MemoryContext oldCxt = MemoryContextSwitchTo(insertCtx);
651682

652-
foreach(l, incomplete_inserts) {
683+
/* we should call gistContinueInsert in reverse order */
684+
685+
foreach(l, incomplete_inserts)
686+
reverse = lappend(reverse, lfirst(l));
687+
688+
MemoryContextSwitchTo(opCtx);
689+
foreach(l, reverse) {
653690
gistIncompleteInsert *insert = (gistIncompleteInsert*) lfirst(l);
654691
gistContinueInsert(insert);
692+
MemoryContextReset(opCtx);
655693
}
694+
MemoryContextSwitchTo(oldCxt);
695+
656696
MemoryContextDelete(opCtx);
657697
MemoryContextDelete(insertCtx);
658698
}

src/include/access/gist.h

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
1010
* Portions Copyright (c) 1994, Regents of the University of California
1111
*
12-
* $PostgreSQL: pgsql/src/include/access/gist.h,v 1.48 2005/06/27 12:45:22 teodor Exp $
12+
* $PostgreSQL: pgsql/src/include/access/gist.h,v 1.49 2005/06/30 17:52:14 teodor Exp $
1313
*
1414
*-------------------------------------------------------------------------
1515
*/
@@ -45,13 +45,7 @@ typedef XLogRecPtr GistNSN;
4545

4646
typedef struct GISTPageOpaqueData
4747
{
48-
uint8 flags;
49-
50-
/* number page to which current one is splitted in last split */
51-
uint8 nsplited;
52-
53-
/* level of page, 0 - leaf */
54-
uint16 level;
48+
uint32 flags; /* 29 bits are unused for now */
5549
BlockNumber rightlink;
5650

5751
/* the only meaning - change this value if

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