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);
*/
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. */
*/
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);
}
/*
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 ********/
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
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);
-}