diff --git a/src/backend/access/heap/hio.c b/src/backend/access/heap/hio.c index 42e75ec0b67..b8b5871559b 100644 --- a/src/backend/access/heap/hio.c +++ b/src/backend/access/heap/hio.c @@ -177,13 +177,10 @@ GetVisibilityMapPins(Relation relation, Buffer buffer1, Buffer buffer2, static void RelationAddExtraBlocks(Relation relation, BulkInsertState bistate) { - Page page; - BlockNumber blockNum = InvalidBlockNumber, + BlockNumber blockNum, firstBlock = InvalidBlockNumber; - int extraBlocks = 0; - int lockWaiters = 0; - Size freespace = 0; - Buffer buffer; + int extraBlocks; + int lockWaiters; /* Use the length of the lock wait queue to judge how much to extend. */ lockWaiters = RelationExtensionLockWaiterCount(relation); @@ -198,18 +195,40 @@ RelationAddExtraBlocks(Relation relation, BulkInsertState bistate) */ extraBlocks = Min(512, lockWaiters * 20); - while (extraBlocks-- >= 0) + do { - /* Ouch - an unnecessary lseek() each time through the loop! */ + Buffer buffer; + Page page; + Size freespace; + + /* + * Extend by one page. This should generally match the main-line + * extension code in RelationGetBufferForTuple, except that we hold + * the relation extension lock throughout. + */ buffer = ReadBufferBI(relation, P_NEW, bistate); - /* Extend by one page. */ LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE); page = BufferGetPage(buffer); + + if (!PageIsNew(page)) + elog(ERROR, "page %u of relation \"%s\" should be empty but is not", + BufferGetBlockNumber(buffer), + RelationGetRelationName(relation)); + PageInit(page, BufferGetPageSize(buffer), 0); + + /* + * We mark all the new buffers dirty, but do nothing to write them + * out; they'll probably get used soon, and even if they are not, a + * crash will leave an okay all-zeroes page on disk. + */ MarkBufferDirty(buffer); + + /* we'll need this info below */ blockNum = BufferGetBlockNumber(buffer); freespace = PageGetHeapFreeSpace(page); + UnlockReleaseBuffer(buffer); /* Remember first block number thus added. */ @@ -223,18 +242,15 @@ RelationAddExtraBlocks(Relation relation, BulkInsertState bistate) */ RecordPageWithFreeSpace(relation, blockNum, freespace); } + while (--extraBlocks > 0); /* * Updating the upper levels of the free space map is too expensive to do * for every block, but it's worth doing once at the end to make sure that * subsequent insertion activity sees all of those nifty free pages we * just inserted. - * - * Note that we're using the freespace value that was reported for the - * last block we added as if it were the freespace value for every block - * we added. That's actually true, because they're all equally empty. */ - UpdateFreeSpaceMap(relation, firstBlock, blockNum, freespace); + FreeSpaceMapVacuumRange(relation, firstBlock, blockNum + 1); } /* diff --git a/src/backend/storage/freespace/freespace.c b/src/backend/storage/freespace/freespace.c index 7eb4f3ee930..fd18c851140 100644 --- a/src/backend/storage/freespace/freespace.c +++ b/src/backend/storage/freespace/freespace.c @@ -111,8 +111,6 @@ static BlockNumber fsm_search(Relation rel, uint8 min_cat); static uint8 fsm_vacuum_page(Relation rel, FSMAddress addr, BlockNumber start, BlockNumber end, bool *eof); -static BlockNumber fsm_get_lastblckno(Relation rel, FSMAddress addr); -static void fsm_update_recursive(Relation rel, FSMAddress addr, uint8 new_cat); /******** Public API ********/ @@ -192,46 +190,6 @@ RecordPageWithFreeSpace(Relation rel, BlockNumber heapBlk, Size spaceAvail) fsm_set_and_search(rel, addr, slot, new_cat, 0); } -/* - * Update the upper levels of the free space map all the way up to the root - * to make sure we don't lose track of new blocks we just inserted. This is - * intended to be used after adding many new blocks to the relation; we judge - * it not worth updating the upper levels of the tree every time data for - * a single page changes, but for a bulk-extend it's worth it. - */ -void -UpdateFreeSpaceMap(Relation rel, BlockNumber startBlkNum, - BlockNumber endBlkNum, Size freespace) -{ - int new_cat = fsm_space_avail_to_cat(freespace); - FSMAddress addr; - uint16 slot; - BlockNumber blockNum; - BlockNumber lastBlkOnPage; - - blockNum = startBlkNum; - - while (blockNum <= endBlkNum) - { - /* - * Find FSM address for this block; update tree all the way to the - * root. - */ - addr = fsm_get_location(blockNum, &slot); - fsm_update_recursive(rel, addr, new_cat); - - /* - * Get the last block number on this FSM page. If that's greater than - * or equal to our endBlkNum, we're done. Otherwise, advance to the - * first block on the next page. - */ - lastBlkOnPage = fsm_get_lastblckno(rel, addr); - if (lastBlkOnPage >= endBlkNum) - break; - blockNum = lastBlkOnPage + 1; - } -} - /* * XLogRecordPageWithFreeSpace - like RecordPageWithFreeSpace, for use in * WAL replay @@ -929,42 +887,3 @@ fsm_vacuum_page(Relation rel, FSMAddress addr, return max_avail; } - -/* - * This function will return the last block number stored on given - * FSM page address. - */ -static BlockNumber -fsm_get_lastblckno(Relation rel, FSMAddress addr) -{ - int slot; - - /* - * Get the last slot number on the given address and convert that to block - * number - */ - slot = SlotsPerFSMPage - 1; - return fsm_get_heap_blk(addr, slot); -} - -/* - * Recursively update the FSM tree from given address to - * all the way up to root. - */ -static void -fsm_update_recursive(Relation rel, FSMAddress addr, uint8 new_cat) -{ - uint16 parentslot; - FSMAddress parent; - - if (addr.level == FSM_ROOT_LEVEL) - return; - - /* - * Get the parent page and our slot in the parent page, and update the - * information in that. - */ - parent = fsm_get_parent(addr, &parentslot); - fsm_set_and_search(rel, parent, parentslot, new_cat, 0); - fsm_update_recursive(rel, parent, new_cat); -} diff --git a/src/include/storage/freespace.h b/src/include/storage/freespace.h index a2032518ac2..726eb30fb80 100644 --- a/src/include/storage/freespace.h +++ b/src/include/storage/freespace.h @@ -34,9 +34,5 @@ extern void FreeSpaceMapTruncateRel(Relation rel, BlockNumber nblocks); extern void FreeSpaceMapVacuum(Relation rel); extern void FreeSpaceMapVacuumRange(Relation rel, BlockNumber start, BlockNumber end); -extern void UpdateFreeSpaceMap(Relation rel, - BlockNumber startBlkNum, - BlockNumber endBlkNum, - Size freespace); #endif /* FREESPACE_H_ */