diff options
author | Heikki Linnakangas <heikki.linnakangas@iki.fi> | 2015-07-27 12:28:21 +0300 |
---|---|---|
committer | Heikki Linnakangas <heikki.linnakangas@iki.fi> | 2015-07-27 12:28:21 +0300 |
commit | 023430abf72eb7d335430e241065d5ed19ddd94b (patch) | |
tree | 4fb0719906779bc0db720dcda1fb8b3f308f7053 /src/backend/access/spgist | |
parent | 65c384c5abee7df6d27f98135790ea24c1b9578b (diff) | |
download | postgresql-023430abf72eb7d335430e241065d5ed19ddd94b.tar.gz postgresql-023430abf72eb7d335430e241065d5ed19ddd94b.zip |
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.
Diffstat (limited to 'src/backend/access/spgist')
-rw-r--r-- | src/backend/access/spgist/spgvacuum.c | 27 |
1 files changed, 8 insertions, 19 deletions
diff --git a/src/backend/access/spgist/spgvacuum.c b/src/backend/access/spgist/spgvacuum.c index dc69d1ed20f..d40da0eecca 100644 --- a/src/backend/access/spgist/spgvacuum.c +++ b/src/backend/access/spgist/spgvacuum.c @@ -621,14 +621,10 @@ spgvacuumpage(spgBulkDeleteState *bds, BlockNumber blkno) { /* * We found an all-zero page, which could happen if the database - * crashed just after extending the file. Initialize and recycle it. + * crashed just after extending the file. Recycle it. */ - SpGistInitBuffer(buffer, 0); - SpGistPageSetDeleted(page); - /* We don't bother to WAL-log this action; easy to redo */ - MarkBufferDirty(buffer); } - else if (SpGistPageIsDeleted(page)) + else if (PageIsEmpty(page)) { /* nothing to do */ } @@ -654,30 +650,23 @@ spgvacuumpage(spgBulkDeleteState *bds, BlockNumber blkno) /* * The root pages must never be deleted, nor marked as available in FSM, * because we don't want them ever returned by a search for a place to put - * a new tuple. Otherwise, check for empty/deletable page, and make sure - * FSM knows about it. + * a new tuple. Otherwise, check for empty page, and make sure the FSM + * knows about it. */ if (!SpGistBlockIsRoot(blkno)) { - /* If page is now empty, mark it deleted */ - if (PageIsEmpty(page) && !SpGistPageIsDeleted(page)) - { - SpGistPageSetDeleted(page); - /* We don't bother to WAL-log this action; easy to redo */ - MarkBufferDirty(buffer); - } - - if (SpGistPageIsDeleted(page)) + if (PageIsEmpty(page)) { RecordFreeIndexPage(index, blkno); bds->stats->pages_deleted++; } else + { + SpGistSetLastUsedPage(index, buffer); bds->lastFilledBlock = blkno; + } } - SpGistSetLastUsedPage(index, buffer); - UnlockReleaseBuffer(buffer); } |