@@ -188,7 +188,9 @@ static bool heap_page_will_set_vis(Relation relation,
188188								   Buffer  heap_buf ,
189189								   Buffer  vmbuffer ,
190190								   bool  blk_known_av ,
191- 								   const  PruneState  * prstate ,
191+ 								   PruneReason  reason ,
192+ 								   bool  do_prune , bool  do_freeze ,
193+ 								   PruneState  * prstate ,
192194								   uint8  * vmflags ,
193195								   bool  * do_set_pd_vis );
194196
@@ -203,9 +205,13 @@ static bool heap_page_will_set_vis(Relation relation,
203205 * if there's not any use in pruning. 
204206 * 
205207 * Caller must have pin on the buffer, and must *not* have a lock on it. 
208+  * 
209+  * If vmbuffer is not NULL, it is okay for pruning to set the visibility map if 
210+  * the page is all-visible. We will take care of pinning and, if needed, 
211+  * reading in the page of the visibility map. 
206212 */ 
207213void 
208- heap_page_prune_opt (Relation  relation , Buffer  buffer )
214+ heap_page_prune_opt (Relation  relation , Buffer  buffer ,  Buffer   * vmbuffer )
209215{
210216	Page 		page  =  BufferGetPage (buffer );
211217	TransactionId  prune_xid ;
@@ -271,12 +277,21 @@ heap_page_prune_opt(Relation relation, Buffer buffer)
271277			PruneFreezeParams  params ;
272278			PruneFreezeResult  presult ;
273279
280+ 			params .options  =  0 ;
281+ 			params .vmbuffer  =  InvalidBuffer ;
282+ 
283+ 			if  (vmbuffer )
284+ 			{
285+ 				visibilitymap_pin (relation , BufferGetBlockNumber (buffer ), vmbuffer );
286+ 				params .options  =  HEAP_PAGE_PRUNE_UPDATE_VIS ;
287+ 				params .vmbuffer  =  * vmbuffer ;
288+ 			}
289+ 
274290			params .relation  =  relation ;
275291			params .buffer  =  buffer ;
276292			params .reason  =  PRUNE_ON_ACCESS ;
277293			params .vistest  =  vistest ;
278294			params .cutoffs  =  NULL ;
279- 			params .vmbuffer  =  InvalidBuffer ;
280295			params .blk_known_av  =  false;
281296
282297			/* 
@@ -456,6 +471,9 @@ heap_page_will_freeze(Relation relation, Buffer buffer,
456471 * have examined this page’s VM bits (e.g., VACUUM in the previous 
457472 * heap_vac_scan_next_block() call) and can pass that along. 
458473 * 
474+  * This should be called only after do_freeze has been decided (and do_prune 
475+  * has been set), as these factor into our heuristic-based decision. 
476+  * 
459477 * Returns true if one or both VM bits should be set, along with the desired 
460478 * flags in *vmflags. Also indicates via do_set_pd_vis whether PD_ALL_VISIBLE 
461479 * should be set on the heap page. 
@@ -466,7 +484,9 @@ heap_page_will_set_vis(Relation relation,
466484					   Buffer  heap_buf ,
467485					   Buffer  vmbuffer ,
468486					   bool  blk_known_av ,
469- 					   const  PruneState  * prstate ,
487+ 					   PruneReason  reason ,
488+ 					   bool  do_prune , bool  do_freeze ,
489+ 					   PruneState  * prstate ,
470490					   uint8  * vmflags ,
471491					   bool  * do_set_pd_vis )
472492{
@@ -482,6 +502,23 @@ heap_page_will_set_vis(Relation relation,
482502		return  false;
483503	}
484504
505+ 	/* 
506+ 	 * If this is an on-access call and we're not actually pruning, avoid 
507+ 	 * setting the visibility map if it would newly dirty the heap page or, if 
508+ 	 * the page is already dirty, if doing so would require including a 
509+ 	 * full-page image (FPI) of the heap page in the WAL. This situation 
510+ 	 * should be rare, as on-access pruning is only attempted when 
511+ 	 * pd_prune_xid is valid. 
512+ 	 */ 
513+ 	if  (reason  ==  PRUNE_ON_ACCESS  && 
514+ 		prstate -> all_visible  && 
515+ 		!do_prune  &&  !do_freeze  && 
516+ 		(!BufferIsDirty (heap_buf ) ||  XLogCheckBufferNeedsBackup (heap_buf )))
517+ 	{
518+ 		prstate -> all_visible  =  prstate -> all_frozen  =  false;
519+ 		return  false;
520+ 	}
521+ 
485522	if  (prstate -> all_visible  &&  !PageIsAllVisible (heap_page ))
486523		* do_set_pd_vis  =  true;
487524
@@ -505,6 +542,11 @@ heap_page_will_set_vis(Relation relation,
505542	 * page-level bit is clear.  However, it's possible that in vacuum the bit 
506543	 * got cleared after heap_vac_scan_next_block() was called, so we must 
507544	 * recheck with buffer lock before concluding that the VM is corrupt. 
545+ 	 * 
546+ 	 * This will never trigger for on-access pruning because it couldn't have 
547+ 	 * done a previous visibility map lookup and thus will always pass 
548+ 	 * blk_known_av as false. A future vacuum will have to take care of fixing 
549+ 	 * the corruption. 
508550	 */ 
509551	else  if  (blk_known_av  &&  !PageIsAllVisible (heap_page ) && 
510552			 visibilitymap_get_status (relation , heap_blk , & vmbuffer ) !=  0 )
@@ -913,6 +955,14 @@ heap_page_prune_and_freeze(PruneFreezeParams *params,
913955		prstate .ndead  >  0  || 
914956		prstate .nunused  >  0 ;
915957
958+ 	/* 
959+ 	 * Even if we don't prune anything, if we found a new value for the 
960+ 	 * pd_prune_xid field or the page was marked full, we will update the hint 
961+ 	 * bit. 
962+ 	 */ 
963+ 	do_hint_prune  =  ((PageHeader ) page )-> pd_prune_xid  !=  prstate .new_prune_xid  || 
964+ 		PageIsFull (page );
965+ 
916966	/* 
917967	 * After processing all the live tuples on the page, if the newest xmin 
918968	 * amongst them is not visible to everyone, the page cannot be 
@@ -923,14 +973,6 @@ heap_page_prune_and_freeze(PruneFreezeParams *params,
923973		!GlobalVisXidVisibleToAll (prstate .vistest , prstate .visibility_cutoff_xid ))
924974		prstate .all_visible  =  prstate .all_frozen  =  false;
925975
926- 	/* 
927- 	 * Even if we don't prune anything, if we found a new value for the 
928- 	 * pd_prune_xid field or the page was marked full, we will update the hint 
929- 	 * bit. 
930- 	 */ 
931- 	do_hint_prune  =  ((PageHeader ) page )-> pd_prune_xid  !=  prstate .new_prune_xid  || 
932- 		PageIsFull (page );
933- 
934976	/* 
935977	 * Decide if we want to go ahead with freezing according to the freeze 
936978	 * plans we prepared, or not. 
@@ -974,6 +1016,7 @@ heap_page_prune_and_freeze(PruneFreezeParams *params,
9741016	 */ 
9751017	do_set_vm  =  heap_page_will_set_vis (params -> relation ,
9761018									   blockno , buffer , vmbuffer , params -> blk_known_av ,
1019+ 									   params -> reason , do_prune , do_freeze ,
9771020									   & prstate , & new_vmbits , & do_set_pd_vis );
9781021
9791022	/* We should only set the VM if PD_ALL_VISIBLE is set or will be */ 
@@ -2250,7 +2293,7 @@ heap_log_freeze_plan(HeapTupleFreeze *tuples, int ntuples,
22502293
22512294/* 
22522295 * Calculate the conflict horizon for the whole XLOG_HEAP2_PRUNE_VACUUM_SCAN 
2253-  * record. 
2296+  * or XLOG_HEAP2_PRUNE_ON_ACCESS  record. 
22542297 */ 
22552298static  TransactionId 
22562299get_conflict_xid (bool  do_prune , bool  do_freeze , bool  do_set_vm ,
@@ -2319,8 +2362,8 @@ get_conflict_xid(bool do_prune, bool do_freeze, bool do_set_vm,
23192362 * - Reaping: During vacuum phase III, items that are already LP_DEAD are 
23202363 *   marked as unused. 
23212364 * 
2322-  * - VM updates: After vacuum phases I and III, the heap page may be marked  
2323-  *   all-visible and all-frozen. 
2365+  * - VM updates: After vacuum phases I and III and on-access , the heap page 
2366+  *   may be marked  all-visible and all-frozen. 
23242367 * 
23252368 * These changes all happen together, so we use a single WAL record for them 
23262369 * all. 
0 commit comments