Skip to content

Commit 579b9f9

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 491c24f commit 579b9f9

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
@@ -618,14 +618,10 @@ spgvacuumpage(spgBulkDeleteState *bds, BlockNumber blkno)
618618
{
619619
/*
620620
* We found an all-zero page, which could happen if the database
621-
* crashed just after extending the file. Initialize and recycle it.
621+
* crashed just after extending the file. Recycle it.
622622
*/
623-
SpGistInitBuffer(buffer, 0);
624-
SpGistPageSetDeleted(page);
625-
/* We don't bother to WAL-log this action; easy to redo */
626-
MarkBufferDirty(buffer);
627623
}
628-
else if (SpGistPageIsDeleted(page))
624+
else if (PageIsEmpty(page))
629625
{
630626
/* nothing to do */
631627
}
@@ -651,30 +647,23 @@ spgvacuumpage(spgBulkDeleteState *bds, BlockNumber blkno)
651647
/*
652648
* The root pages must never be deleted, nor marked as available in FSM,
653649
* because we don't want them ever returned by a search for a place to put
654-
* a new tuple. Otherwise, check for empty/deletable page, and make sure
655-
* FSM knows about it.
650+
* a new tuple. Otherwise, check for empty page, and make sure the FSM
651+
* knows about it.
656652
*/
657653
if (!SpGistBlockIsRoot(blkno))
658654
{
659-
/* If page is now empty, mark it deleted */
660-
if (PageIsEmpty(page) && !SpGistPageIsDeleted(page))
661-
{
662-
SpGistPageSetDeleted(page);
663-
/* We don't bother to WAL-log this action; easy to redo */
664-
MarkBufferDirty(buffer);
665-
}
666-
667-
if (SpGistPageIsDeleted(page))
655+
if (PageIsEmpty(page))
668656
{
669657
RecordFreeIndexPage(index, blkno);
670658
bds->stats->pages_deleted++;
671659
}
672660
else
661+
{
662+
SpGistSetLastUsedPage(index, buffer);
673663
bds->lastFilledBlock = blkno;
664+
}
674665
}
675666

676-
SpGistSetLastUsedPage(index, buffer);
677-
678667
UnlockReleaseBuffer(buffer);
679668
}
680669

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)
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