summaryrefslogtreecommitdiff
path: root/src/backend/storage/freespace/freespace.c
diff options
context:
space:
mode:
authorRobert Haas <rhaas@postgresql.org>2016-04-08 02:04:46 -0400
committerRobert Haas <rhaas@postgresql.org>2016-04-08 02:04:46 -0400
commit719c84c1be51f3d3fe6049b77ddbaa0c4b58a9a9 (patch)
treec2f4b1501655e50339e3365f267fcce00fd06bbb /src/backend/storage/freespace/freespace.c
parent8643b91ecf8f47a1307df4a00d66b2fceada0d6f (diff)
Extend relations multiple blocks at a time to improve scalability.
Contention on the relation extension lock can become quite fierce when multiple processes are inserting data into the same relation at the same time at a high rate. Experimentation shows the extending the relation multiple blocks at a time improves scalability. Dilip Kumar, reviewed by Petr Jelinek, Amit Kapila, and me.
Diffstat (limited to 'src/backend/storage/freespace/freespace.c')
-rw-r--r--src/backend/storage/freespace/freespace.c81
1 files changed, 81 insertions, 0 deletions
diff --git a/src/backend/storage/freespace/freespace.c b/src/backend/storage/freespace/freespace.c
index 813990ea707..2ffa8ff24d0 100644
--- a/src/backend/storage/freespace/freespace.c
+++ b/src/backend/storage/freespace/freespace.c
@@ -109,6 +109,8 @@ static int fsm_set_and_search(Relation rel, FSMAddress addr, uint16 slot,
uint8 newValue, uint8 minValue);
static BlockNumber fsm_search(Relation rel, uint8 min_cat);
static uint8 fsm_vacuum_page(Relation rel, FSMAddress addr, 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 ********/
@@ -189,6 +191,46 @@ RecordPageWithFreeSpace(Relation rel, BlockNumber heapBlk, Size spaceAvail)
}
/*
+ * 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
*/
@@ -788,3 +830,42 @@ fsm_vacuum_page(Relation rel, FSMAddress addr, bool *eof_p)
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);
+}