@@ -860,65 +860,43 @@ lazy_scan_heap(Relation onerel, int options, LVRelStats *vacrelstats,
860
860
861
861
if (PageIsNew (page ))
862
862
{
863
- bool still_new ;
864
-
865
863
/*
866
- * All-zeroes pages can be left over if either a backend extends
867
- * the relation by a single page, but crashes before the newly
868
- * initialized page has been written out, or when bulk-extending
869
- * the relation (which creates a number of empty pages at the tail
870
- * end of the relation, but enters them into the FSM).
871
- *
872
- * Make sure these pages are in the FSM, to ensure they can be
873
- * reused. Do that by testing if there's any space recorded for
874
- * the page. If not, enter it.
875
- *
876
- * Note we do not enter the page into the visibilitymap. That has
877
- * the downside that we repeatedly visit this page in subsequent
878
- * vacuums, but otherwise we'll never not discover the space on a
879
- * promoted standby. The harm of repeated checking ought to
880
- * normally not be too bad - the space usually should be used at
881
- * some point, otherwise there wouldn't be any regular vacuums.
864
+ * An all-zeroes page could be left over if a backend extends the
865
+ * relation but crashes before initializing the page. Reclaim such
866
+ * pages for use.
882
867
*
883
868
* We have to be careful here because we could be looking at a
884
- * page that someone has just added to the relation and the
885
- * extending backend might not yet have been able to lock the page
886
- * (see RelationGetBufferForTuple), which is problematic because
887
- * of cross-checks that new pages are actually new . If we add this
888
- * page to the FSM, this page could be reused, and such
889
- * crosschecks could fail. To protect against that, release the
890
- * buffer lock, grab the relation extension lock momentarily, and
891
- * re-lock the buffer. If the page is still empty and not in the
892
- * FSM by then, it must be left over from a from a crashed
893
- * backend, and we can record the free space .
869
+ * page that someone has just added to the relation and not yet
870
+ * been able to initialize (see RelationGetBufferForTuple). To
871
+ * protect against that, release the buffer lock, grab the
872
+ * relation extension lock momentarily, and re-lock the buffer . If
873
+ * the page is still uninitialized by then, it must be left over
874
+ * from a crashed backend, and we can initialize it.
875
+ *
876
+ * We don't really need the relation lock when this is a new or
877
+ * temp relation, but it's probably not worth the code space to
878
+ * check that, since this surely isn't a critical path .
894
879
*
895
880
* Note: the comparable code in vacuum.c need not worry because
896
- * it's got an exclusive lock on the whole relation.
881
+ * it's got exclusive lock on the whole relation.
897
882
*/
898
883
LockBuffer (buf , BUFFER_LOCK_UNLOCK );
899
884
LockRelationForExtension (onerel , ExclusiveLock );
900
885
UnlockRelationForExtension (onerel , ExclusiveLock );
901
886
LockBufferForCleanup (buf );
902
-
903
- /*
904
- * Perform checking of FSM after releasing lock, the fsm is
905
- * approximate, after all.
906
- */
907
- still_new = PageIsNew (page );
908
- UnlockReleaseBuffer (buf );
909
-
910
- if (still_new )
887
+ if (PageIsNew (page ))
911
888
{
889
+ ereport (WARNING ,
890
+ (errmsg ("relation \"%s\" page %u is uninitialized --- fixing" ,
891
+ relname , blkno )));
892
+ PageInit (page , BufferGetPageSize (buf ), 0 );
912
893
empty_pages ++ ;
913
-
914
- if (GetRecordedFreeSpace (onerel , blkno ) == 0 )
915
- {
916
- Size freespace ;
917
-
918
- freespace = BufferGetPageSize (buf ) - SizeOfPageHeaderData ;
919
- RecordPageWithFreeSpace (onerel , blkno , freespace );
920
- }
921
894
}
895
+ freespace = PageGetHeapFreeSpace (page );
896
+ MarkBufferDirty (buf );
897
+ UnlockReleaseBuffer (buf );
898
+
899
+ RecordPageWithFreeSpace (onerel , blkno , freespace );
922
900
continue ;
923
901
}
924
902
@@ -927,10 +905,7 @@ lazy_scan_heap(Relation onerel, int options, LVRelStats *vacrelstats,
927
905
empty_pages ++ ;
928
906
freespace = PageGetHeapFreeSpace (page );
929
907
930
- /*
931
- * Empty pages are always all-visible and all-frozen (note that
932
- * the same is currently not true for new pages, see above).
933
- */
908
+ /* empty pages are always all-visible and all-frozen */
934
909
if (!PageIsAllVisible (page ))
935
910
{
936
911
START_CRIT_SECTION ();
@@ -1664,13 +1639,12 @@ lazy_check_needs_freeze(Buffer buf, bool *hastup)
1664
1639
1665
1640
* hastup = false;
1666
1641
1667
- /*
1668
- * New and empty pages, obviously, don't contain tuples. We could make
1669
- * sure that the page is registered in the FSM, but it doesn't seem worth
1670
- * waiting for a cleanup lock just for that, especially because it's
1671
- * likely that the pin holder will do so.
1672
- */
1673
- if (PageIsNew (page ) || PageIsEmpty (page ))
1642
+ /* If we hit an uninitialized page, we want to force vacuuming it. */
1643
+ if (PageIsNew (page ))
1644
+ return true;
1645
+
1646
+ /* Quick out for ordinary empty page. */
1647
+ if (PageIsEmpty (page ))
1674
1648
return false;
1675
1649
1676
1650
maxoff = PageGetMaxOffsetNumber (page );
@@ -2055,6 +2029,7 @@ count_nondeletable_pages(Relation onerel, LVRelStats *vacrelstats)
2055
2029
2056
2030
if (PageIsNew (page ) || PageIsEmpty (page ))
2057
2031
{
2032
+ /* PageIsNew probably shouldn't happen... */
2058
2033
UnlockReleaseBuffer (buf );
2059
2034
continue ;
2060
2035
}
0 commit comments