So here's my attempt to rewrite this logic. I ended up refactoring a
bit because I found it unnecessarily confusing having the mode
branches in several places. I think it's much clearer just having two
separate pieces of logic for RBM_NEW and the extension cases since all
they have in common is the ReadBuffer call.
I have to say, it scares the hell out of me that there are no
regression tests for this code. I'm certainly not comfortable
committing it without a few other people reading it if I haven't even
run the code once. At least I know it compiles...
*** a/src/backend/access/transam/xlogutils.c
--- b/src/backend/access/transam/xlogutils.c
***************
*** 293,300 **** Buffer
XLogReadBufferExtended(RelFileNode rnode, ForkNumber forknum,
BlockNumber blkno, ReadBufferMode mode)
{
- BlockNumber lastblock;
Buffer buffer;
SMgrRelation smgr;
Assert(blkno != P_NEW);
--- 293,300 ----
XLogReadBufferExtended(RelFileNode rnode, ForkNumber forknum,
BlockNumber blkno, ReadBufferMode mode)
{
Buffer buffer;
+ Page page;
SMgrRelation smgr;
Assert(blkno != P_NEW);
***************
*** 312,353 **** XLogReadBufferExtended(RelFileNode rnode, ForkNumber forknum,
*/
smgrcreate(smgr, forknum, true);
! lastblock = smgrnblocks(smgr, forknum);
!
! if (blkno < lastblock)
! {
! /* page exists in file */
! buffer = ReadBufferWithoutRelcache(rnode, forknum, blkno,
! mode, NULL);
! }
! else
{
/* hm, page doesn't exist in file */
! if (mode == RBM_NORMAL)
{
log_invalid_page(rnode, forknum, blkno, false);
return InvalidBuffer;
}
- /* OK to extend the file */
- /* we do this in recovery only - no rel-extension lock needed */
- Assert(InRecovery);
- buffer = InvalidBuffer;
- while (blkno >= lastblock)
- {
- if (buffer != InvalidBuffer)
- ReleaseBuffer(buffer);
- buffer = ReadBufferWithoutRelcache(rnode, forknum,
- P_NEW, mode, NULL);
- lastblock++;
- }
- Assert(BufferGetBlockNumber(buffer) == blkno);
- }
! if (mode == RBM_NORMAL)
! {
! /* check that page has been initialized */
! Page page = (Page) BufferGetPage(buffer);
/*
* We assume that PageIsNew is safe without a lock. During recovery,
* there should be no other backends that could modify the buffer at
--- 312,332 ----
*/
smgrcreate(smgr, forknum, true);
! if (mode == RBM_NORMAL)
{
/* hm, page doesn't exist in file */
! if (blkno >= smgrnblocks(smgr, forknum))
{
log_invalid_page(rnode, forknum, blkno, false);
return InvalidBuffer;
}
! buffer = ReadBufferWithoutRelcache(rnode, forknum, blkno,
! mode, NULL);
+ /* check that page has been initialized */
+ page = (Page) BufferGetPage(buffer);
+
/*
* We assume that PageIsNew is safe without a lock. During recovery,
* there should be no other backends that could modify the buffer at
***************
*** 359,366 **** XLogReadBufferExtended(RelFileNode rnode, ForkNumber forknum,
log_invalid_page(rnode, forknum, blkno, true);
return InvalidBuffer;
}
- }
return buffer;
}
--- 338,364 ----
log_invalid_page(rnode, forknum, blkno, true);
return InvalidBuffer;
}
+ } else {
+
+ /* If page doesn't exist extend the file */
+ while (blkno >= smgrnblocks(smgr, forknum))
+ {
+ /* we do this in recovery only - no rel-extension lock needed */
+ Assert(InRecovery);
+ buffer = ReadBufferWithoutRelcache(rnode, forknum,
+ P_NEW, mode, NULL);
+ /* Take care not to extend the relation past where it's needed */
+ if (BufferGetBlockNumber(buffer) == blkno)
+ return buffer;
+ ReleaseBuffer(buffer);
+ }
+
+ /* page now exists in file */
+ buffer = ReadBufferWithoutRelcache(rnode, forknum, blkno,
+ mode, NULL);
+ }
+
return buffer;
}
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers