@@ -98,7 +98,7 @@ static BlockNumber fsm_get_heap_blk(FSMAddress addr, uint16 slot);
98
98
static BlockNumber fsm_logical_to_physical (FSMAddress addr );
99
99
100
100
static Buffer fsm_readbuf (Relation rel , FSMAddress addr , bool extend );
101
- static void fsm_extend (Relation rel , BlockNumber fsm_nblocks );
101
+ static Buffer fsm_extend (Relation rel , BlockNumber fsm_nblocks );
102
102
103
103
/* functions to convert amount of free space to a FSM category */
104
104
static uint8 fsm_space_avail_to_cat (Size avail );
@@ -558,24 +558,30 @@ fsm_readbuf(Relation rel, FSMAddress addr, bool extend)
558
558
reln -> smgr_cached_nblocks [FSM_FORKNUM ] = 0 ;
559
559
}
560
560
561
- /* Handle requests beyond EOF */
561
+ /*
562
+ * For reading we use ZERO_ON_ERROR mode, and initialize the page if
563
+ * necessary. The FSM information is not accurate anyway, so it's better
564
+ * to clear corrupt pages than error out. Since the FSM changes are not
565
+ * WAL-logged, the so-called torn page problem on crash can lead to pages
566
+ * with corrupt headers, for example.
567
+ *
568
+ * We use the same path below to initialize pages when extending the
569
+ * relation, as a concurrent extension can end up with vm_extend()
570
+ * returning an already-initialized page.
571
+ */
562
572
if (blkno >= reln -> smgr_cached_nblocks [FSM_FORKNUM ])
563
573
{
564
574
if (extend )
565
- fsm_extend (rel , blkno + 1 );
575
+ buf = fsm_extend (rel , blkno + 1 );
566
576
else
567
577
return InvalidBuffer ;
568
578
}
579
+ else
580
+ buf = ReadBufferExtended (rel , FSM_FORKNUM , blkno , RBM_ZERO_ON_ERROR , NULL );
569
581
570
582
/*
571
- * Use ZERO_ON_ERROR mode, and initialize the page if necessary. The FSM
572
- * information is not accurate anyway, so it's better to clear corrupt
573
- * pages than error out. Since the FSM changes are not WAL-logged, the
574
- * so-called torn page problem on crash can lead to pages with corrupt
575
- * headers, for example.
576
- *
577
- * The initialize-the-page part is trickier than it looks, because of the
578
- * possibility of multiple backends doing this concurrently, and our
583
+ * Initializing the page when needed is trickier than it looks, because of
584
+ * the possibility of multiple backends doing this concurrently, and our
579
585
* desire to not uselessly take the buffer lock in the normal path where
580
586
* the page is OK. We must take the lock to initialize the page, so
581
587
* recheck page newness after we have the lock, in case someone else
@@ -588,7 +594,6 @@ fsm_readbuf(Relation rel, FSMAddress addr, bool extend)
588
594
* long as it doesn't depend on the page header having correct contents.
589
595
* Current usage is safe because PageGetContents() does not require that.
590
596
*/
591
- buf = ReadBufferExtended (rel , FSM_FORKNUM , blkno , RBM_ZERO_ON_ERROR , NULL );
592
597
if (PageIsNew (BufferGetPage (buf )))
593
598
{
594
599
LockBuffer (buf , BUFFER_LOCK_EXCLUSIVE );
@@ -604,56 +609,14 @@ fsm_readbuf(Relation rel, FSMAddress addr, bool extend)
604
609
* it if necessary with empty pages. And by empty, I mean pages filled
605
610
* with zeros, meaning there's no free space.
606
611
*/
607
- static void
612
+ static Buffer
608
613
fsm_extend (Relation rel , BlockNumber fsm_nblocks )
609
614
{
610
- BlockNumber fsm_nblocks_now ;
611
- PGAlignedBlock pg = {0 };
612
- SMgrRelation reln ;
613
-
614
-
615
- /*
616
- * We use the relation extension lock to lock out other backends trying to
617
- * extend the FSM at the same time. It also locks out extension of the
618
- * main fork, unnecessarily, but extending the FSM happens seldom enough
619
- * that it doesn't seem worthwhile to have a separate lock tag type for
620
- * it.
621
- *
622
- * Note that another backend might have extended or created the relation
623
- * by the time we get the lock.
624
- */
625
- LockRelationForExtension (rel , ExclusiveLock );
626
-
627
- /*
628
- * Caution: re-using this smgr pointer could fail if the relcache entry
629
- * gets closed. It's safe as long as we only do smgr-level operations
630
- * between here and the last use of the pointer.
631
- */
632
- reln = RelationGetSmgr (rel );
633
-
634
- /*
635
- * Create the FSM file first if it doesn't exist. If
636
- * smgr_cached_nblocks[FSM_FORKNUM] is positive then it must exist, no
637
- * need for an smgrexists call.
638
- */
639
- if ((reln -> smgr_cached_nblocks [FSM_FORKNUM ] == 0 ||
640
- reln -> smgr_cached_nblocks [FSM_FORKNUM ] == InvalidBlockNumber ) &&
641
- !smgrexists (reln , FSM_FORKNUM ))
642
- smgrcreate (reln , FSM_FORKNUM , false);
643
-
644
- /* Invalidate cache so that smgrnblocks() asks the kernel. */
645
- reln -> smgr_cached_nblocks [FSM_FORKNUM ] = InvalidBlockNumber ;
646
- fsm_nblocks_now = smgrnblocks (reln , FSM_FORKNUM );
647
-
648
- /* Extend as needed. */
649
- while (fsm_nblocks_now < fsm_nblocks )
650
- {
651
- smgrextend (reln , FSM_FORKNUM , fsm_nblocks_now ,
652
- pg .data , false);
653
- fsm_nblocks_now ++ ;
654
- }
655
-
656
- UnlockRelationForExtension (rel , ExclusiveLock );
615
+ return ExtendBufferedRelTo (EB_REL (rel ), FSM_FORKNUM , NULL ,
616
+ EB_CREATE_FORK_IF_NEEDED |
617
+ EB_CLEAR_SIZE_CACHE ,
618
+ fsm_nblocks ,
619
+ RBM_ZERO_ON_ERROR );
657
620
}
658
621
659
622
/*
0 commit comments