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

Commit 863af3a

Browse files
committed
Fix handling of all-zero pages in SP-GiST vacuum.
SP-GiST initialized an all-zeros page at vacuum, but that was not WAL-logged, which is not safe. You might get a torn page write, when it gets flushed to disk, and end-up with a half-initialized index page. To fix, leave it in the all-zeros state, and add it to the FSM. It will be initialized when reused. Also don't set the page-deleted flag when recycling an empty page. That was also not WAL-logged, and a torn write of that would cause the page to have an invalid checksum. Backpatch to 9.2, where SP-GiST indexes were added.
1 parent 8352b14 commit 863af3a

File tree

2 files changed

+10
-21
lines changed

2 files changed

+10
-21
lines changed

src/backend/access/spgist/spgvacuum.c

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -619,14 +619,10 @@ spgvacuumpage(spgBulkDeleteState *bds, BlockNumber blkno)
619619
{
620620
/*
621621
* We found an all-zero page, which could happen if the database
622-
* crashed just after extending the file. Initialize and recycle it.
622+
* crashed just after extending the file. Recycle it.
623623
*/
624-
SpGistInitBuffer(buffer, 0);
625-
SpGistPageSetDeleted(page);
626-
/* We don't bother to WAL-log this action; easy to redo */
627-
MarkBufferDirty(buffer);
628624
}
629-
else if (SpGistPageIsDeleted(page))
625+
else if (PageIsEmpty(page))
630626
{
631627
/* nothing to do */
632628
}
@@ -652,30 +648,23 @@ spgvacuumpage(spgBulkDeleteState *bds, BlockNumber blkno)
652648
/*
653649
* The root pages must never be deleted, nor marked as available in FSM,
654650
* because we don't want them ever returned by a search for a place to put
655-
* a new tuple. Otherwise, check for empty/deletable page, and make sure
656-
* FSM knows about it.
651+
* a new tuple. Otherwise, check for empty page, and make sure the FSM
652+
* knows about it.
657653
*/
658654
if (!SpGistBlockIsRoot(blkno))
659655
{
660-
/* If page is now empty, mark it deleted */
661-
if (PageIsEmpty(page) && !SpGistPageIsDeleted(page))
662-
{
663-
SpGistPageSetDeleted(page);
664-
/* We don't bother to WAL-log this action; easy to redo */
665-
MarkBufferDirty(buffer);
666-
}
667-
668-
if (SpGistPageIsDeleted(page))
656+
if (PageIsEmpty(page))
669657
{
670658
RecordFreeIndexPage(index, blkno);
671659
bds->stats->pages_deleted++;
672660
}
673661
else
662+
{
663+
SpGistSetLastUsedPage(index, buffer);
674664
bds->lastFilledBlock = blkno;
665+
}
675666
}
676667

677-
SpGistSetLastUsedPage(index, buffer);
678-
679668
UnlockReleaseBuffer(buffer);
680669
}
681670

src/include/access/spgist_private.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,14 @@ typedef SpGistPageOpaqueData *SpGistPageOpaque;
4848

4949
/* Flag bits in page special space */
5050
#define SPGIST_META (1<<0)
51-
#define SPGIST_DELETED (1<<1)
51+
#define SPGIST_DELETED (1<<1) /* never set, but keep for backwards
52+
* compatibility */
5253
#define SPGIST_LEAF (1<<2)
5354
#define SPGIST_NULLS (1<<3)
5455

5556
#define SpGistPageGetOpaque(page) ((SpGistPageOpaque) PageGetSpecialPointer(page))
5657
#define SpGistPageIsMeta(page) (SpGistPageGetOpaque(page)->flags & SPGIST_META)
5758
#define SpGistPageIsDeleted(page) (SpGistPageGetOpaque(page)->flags & SPGIST_DELETED)
58-
#define SpGistPageSetDeleted(page) (SpGistPageGetOpaque(page)->flags |= SPGIST_DELETED)
5959
#define SpGistPageIsLeaf(page) (SpGistPageGetOpaque(page)->flags & SPGIST_LEAF)
6060
#define SpGistPageStoresNulls(page) (SpGistPageGetOpaque(page)->flags & SPGIST_NULLS)
6161

0 commit comments

Comments
 (0)