Release lock on heap buffer before vacuuming FSM
authorAndres Freund <[email protected]>
Fri, 17 Nov 2023 19:02:52 +0000 (11:02 -0800)
committerAndres Freund <[email protected]>
Fri, 17 Nov 2023 20:46:55 +0000 (12:46 -0800)
When there are no indexes on a table, we vacuum each heap block after
pruning it and then update the freespace map. Periodically, we also
vacuum the freespace map. This was done while unnecessarily holding a
lock on the heap page. Release the lock before calling
FreeSpaceMapVacuumRange() and, while we're at it, ensure the range
includes the heap block we just vacuumed.

There are no known deadlocks or other similar issues, therefore don't
backpatch. It's certainly not good to do all this work under a lock, but it's
not frequently reached, making it not worth the risk of backpatching.

Author: Melanie Plageman <[email protected]>
Reviewed-by: Andres Freund <[email protected]>
Discussion: https://postgr.es/m/CAAKRu_YiL%3D44GvGnt1dpYouDSSoV7wzxVoXs8m3p311rp-TVQQ%40mail.gmail.com

src/backend/access/heap/vacuumlazy.c

index 6985d299b2651820db7ec836d46a114ec5d835d5..59f51f40e1becf2864242b18b1ff42a854df604b 100644 (file)
@@ -1046,18 +1046,6 @@ lazy_scan_heap(LVRelState *vacrel)
                                /* Forget the LP_DEAD items that we just vacuumed */
                                dead_items->num_items = 0;
 
-                               /*
-                                * Periodically perform FSM vacuuming to make newly-freed
-                                * space visible on upper FSM pages.  Note we have not yet
-                                * performed FSM processing for blkno.
-                                */
-                               if (blkno - next_fsm_block_to_vacuum >= VACUUM_FSM_EVERY_PAGES)
-                               {
-                                       FreeSpaceMapVacuumRange(vacrel->rel, next_fsm_block_to_vacuum,
-                                                                                       blkno);
-                                       next_fsm_block_to_vacuum = blkno;
-                               }
-
                                /*
                                 * Now perform FSM processing for blkno, and move on to next
                                 * page.
@@ -1071,6 +1059,24 @@ lazy_scan_heap(LVRelState *vacrel)
 
                                UnlockReleaseBuffer(buf);
                                RecordPageWithFreeSpace(vacrel->rel, blkno, freespace);
+
+                               /*
+                                * Periodically perform FSM vacuuming to make newly-freed
+                                * space visible on upper FSM pages. FreeSpaceMapVacuumRange()
+                                * vacuums the portion of the freespace map covering heap
+                                * pages from start to end - 1. Include the block we just
+                                * vacuumed by passing it blkno + 1. Overflow isn't an issue
+                                * because MaxBlockNumber + 1 is InvalidBlockNumber which
+                                * causes FreeSpaceMapVacuumRange() to vacuum freespace map
+                                * pages covering the remainder of the relation.
+                                */
+                               if (blkno - next_fsm_block_to_vacuum >= VACUUM_FSM_EVERY_PAGES)
+                               {
+                                       FreeSpaceMapVacuumRange(vacrel->rel, next_fsm_block_to_vacuum,
+                                                                                       blkno + 1);
+                                       next_fsm_block_to_vacuum = blkno + 1;
+                               }
+
                                continue;
                        }