summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/brin/brin.c2
-rw-r--r--src/backend/access/brin/brin_pageops.c10
-rw-r--r--src/backend/access/heap/hio.c42
-rw-r--r--src/backend/access/heap/vacuumlazy.c17
-rw-r--r--src/backend/access/transam/xact.c14
-rw-r--r--src/backend/storage/freespace/README38
-rw-r--r--src/backend/storage/freespace/freespace.c301
-rw-r--r--src/backend/storage/freespace/indexfsm.c6
-rw-r--r--src/bin/pg_upgrade/info.c16
-rw-r--r--src/bin/pg_upgrade/pg_upgrade.h6
-rw-r--r--src/bin/pg_upgrade/relfilenode.c63
-rw-r--r--src/include/storage/freespace.h9
-rw-r--r--src/test/regress/expected/fsm.out73
-rw-r--r--src/test/regress/parallel_schedule2
-rw-r--r--src/test/regress/serial_schedule1
-rw-r--r--src/test/regress/sql/fsm.sql66
16 files changed, 49 insertions, 617 deletions
diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c
index 5c2b0c76358..aba234c0af8 100644
--- a/src/backend/access/brin/brin.c
+++ b/src/backend/access/brin/brin.c
@@ -1152,7 +1152,7 @@ terminate_brin_buildstate(BrinBuildState *state)
freespace = PageGetFreeSpace(page);
blk = BufferGetBlockNumber(state->bs_currentInsertBuf);
ReleaseBuffer(state->bs_currentInsertBuf);
- RecordPageWithFreeSpace(state->bs_irel, blk, freespace, InvalidBlockNumber);
+ RecordPageWithFreeSpace(state->bs_irel, blk, freespace);
FreeSpaceMapVacuumRange(state->bs_irel, blk, blk + 1);
}
diff --git a/src/backend/access/brin/brin_pageops.c b/src/backend/access/brin/brin_pageops.c
index 2e83aa42f78..fcc468ced99 100644
--- a/src/backend/access/brin/brin_pageops.c
+++ b/src/backend/access/brin/brin_pageops.c
@@ -310,7 +310,7 @@ brin_doupdate(Relation idxrel, BlockNumber pagesPerRange,
if (extended)
{
- RecordPageWithFreeSpace(idxrel, newblk, freespace, InvalidBlockNumber);
+ RecordPageWithFreeSpace(idxrel, newblk, freespace);
FreeSpaceMapVacuumRange(idxrel, newblk, newblk + 1);
}
@@ -461,7 +461,7 @@ brin_doinsert(Relation idxrel, BlockNumber pagesPerRange,
if (extended)
{
- RecordPageWithFreeSpace(idxrel, blk, freespace, InvalidBlockNumber);
+ RecordPageWithFreeSpace(idxrel, blk, freespace);
FreeSpaceMapVacuumRange(idxrel, blk, blk + 1);
}
@@ -654,7 +654,7 @@ brin_page_cleanup(Relation idxrel, Buffer buf)
/* Measure free space and record it */
RecordPageWithFreeSpace(idxrel, BufferGetBlockNumber(buf),
- br_page_get_freespace(page), InvalidBlockNumber);
+ br_page_get_freespace(page));
}
/*
@@ -703,7 +703,7 @@ brin_getinsertbuffer(Relation irel, Buffer oldbuf, Size itemsz,
/* Choose initial target page, re-using existing target if known */
newblk = RelationGetTargetBlock(irel);
if (newblk == InvalidBlockNumber)
- newblk = GetPageWithFreeSpace(irel, itemsz, true);
+ newblk = GetPageWithFreeSpace(irel, itemsz);
/*
* Loop until we find a page with sufficient free space. By the time we
@@ -895,7 +895,7 @@ brin_initialize_empty_new_buffer(Relation idxrel, Buffer buffer)
* pages whose FSM records were forgotten in a crash.
*/
RecordPageWithFreeSpace(idxrel, BufferGetBlockNumber(buffer),
- br_page_get_freespace(page), InvalidBlockNumber);
+ br_page_get_freespace(page));
}
diff --git a/src/backend/access/heap/hio.c b/src/backend/access/heap/hio.c
index 69a7a23874f..d41d318eef9 100644
--- a/src/backend/access/heap/hio.c
+++ b/src/backend/access/heap/hio.c
@@ -246,14 +246,8 @@ RelationAddExtraBlocks(Relation relation, BulkInsertState bistate)
* Immediately update the bottom level of the FSM. This has a good
* chance of making this page visible to other concurrently inserting
* backends, and we want that to happen without delay.
- *
- * Since we know the table will end up with extraBlocks additional
- * pages, we pass the final number to avoid possible unnecessary
- * system calls and to make sure the FSM is created when we add the
- * first new page.
*/
- RecordPageWithFreeSpace(relation, blockNum, freespace,
- firstBlock + extraBlocks);
+ RecordPageWithFreeSpace(relation, blockNum, freespace);
}
while (--extraBlocks > 0);
@@ -390,9 +384,20 @@ RelationGetBufferForTuple(Relation relation, Size len,
* We have no cached target page, so ask the FSM for an initial
* target.
*/
- targetBlock = GetPageWithFreeSpace(relation,
- len + saveFreeSpace,
- false);
+ targetBlock = GetPageWithFreeSpace(relation, len + saveFreeSpace);
+
+ /*
+ * If the FSM knows nothing of the rel, try the last page before we
+ * give up and extend. This avoids one-tuple-per-page syndrome during
+ * bootstrapping or in a recently-started system.
+ */
+ if (targetBlock == InvalidBlockNumber)
+ {
+ BlockNumber nblocks = RelationGetNumberOfBlocks(relation);
+
+ if (nblocks > 0)
+ targetBlock = nblocks - 1;
+ }
}
loop:
@@ -499,13 +504,6 @@ loop:
{
/* use this page as future insert target, too */
RelationSetTargetBlock(relation, targetBlock);
-
- /*
- * In case we used an in-memory map of available blocks, reset it
- * for next use.
- */
- FSMClearLocalMap();
-
return buffer;
}
@@ -565,12 +563,9 @@ loop:
/*
* Check if some other backend has extended a block for us while
- * we were waiting on the lock. We only check the FSM -- if there
- * isn't one we don't recheck the number of blocks.
+ * we were waiting on the lock.
*/
- targetBlock = GetPageWithFreeSpace(relation,
- len + saveFreeSpace,
- true);
+ targetBlock = GetPageWithFreeSpace(relation, len + saveFreeSpace);
/*
* If some other waiter has already extended the relation, we
@@ -675,8 +670,5 @@ loop:
*/
RelationSetTargetBlock(relation, BufferGetBlockNumber(buffer));
- /* This should already be cleared by now, but make sure it is. */
- FSMClearLocalMap();
-
return buffer;
}
diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c
index 2aa729817cb..0f70dc883d1 100644
--- a/src/backend/access/heap/vacuumlazy.c
+++ b/src/backend/access/heap/vacuumlazy.c
@@ -153,7 +153,7 @@ static BufferAccessStrategy vac_strategy;
static void lazy_scan_heap(Relation onerel, VacuumParams *params,
LVRelStats *vacrelstats, Relation *Irel, int nindexes,
bool aggressive);
-static void lazy_vacuum_heap(Relation onerel, LVRelStats *vacrelstats, BlockNumber nblocks);
+static void lazy_vacuum_heap(Relation onerel, LVRelStats *vacrelstats);
static bool lazy_check_needs_freeze(Buffer buf, bool *hastup);
static void lazy_vacuum_index(Relation indrel,
IndexBulkDeleteResult **stats,
@@ -780,7 +780,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
pgstat_progress_update_multi_param(2, hvp_index, hvp_val);
/* Remove tuples from heap */
- lazy_vacuum_heap(onerel, vacrelstats, nblocks);
+ lazy_vacuum_heap(onerel, vacrelstats);
/*
* Forget the now-vacuumed tuples, and press on, but be careful
@@ -919,7 +919,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
Size freespace;
freespace = BufferGetPageSize(buf) - SizeOfPageHeaderData;
- RecordPageWithFreeSpace(onerel, blkno, freespace, nblocks);
+ RecordPageWithFreeSpace(onerel, blkno, freespace);
}
}
continue;
@@ -963,7 +963,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
}
UnlockReleaseBuffer(buf);
- RecordPageWithFreeSpace(onerel, blkno, freespace, nblocks);
+ RecordPageWithFreeSpace(onerel, blkno, freespace);
continue;
}
@@ -1381,7 +1381,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
* taken if there are no indexes.)
*/
if (vacrelstats->num_dead_tuples == prev_dead_count)
- RecordPageWithFreeSpace(onerel, blkno, freespace, nblocks);
+ RecordPageWithFreeSpace(onerel, blkno, freespace);
}
/* report that everything is scanned and vacuumed */
@@ -1443,7 +1443,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
/* Remove tuples from heap */
pgstat_progress_update_param(PROGRESS_VACUUM_PHASE,
PROGRESS_VACUUM_PHASE_VACUUM_HEAP);
- lazy_vacuum_heap(onerel, vacrelstats, nblocks);
+ lazy_vacuum_heap(onerel, vacrelstats);
vacrelstats->num_index_scans++;
}
@@ -1517,10 +1517,9 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
* Note: the reason for doing this as a second pass is we cannot remove
* the tuples until we've removed their index entries, and we want to
* process index entry removal in batches as large as possible.
- * Note: nblocks is passed as an optimization for RecordPageWithFreeSpace().
*/
static void
-lazy_vacuum_heap(Relation onerel, LVRelStats *vacrelstats, BlockNumber nblocks)
+lazy_vacuum_heap(Relation onerel, LVRelStats *vacrelstats)
{
int tupindex;
int npages;
@@ -1557,7 +1556,7 @@ lazy_vacuum_heap(Relation onerel, LVRelStats *vacrelstats, BlockNumber nblocks)
freespace = PageGetHeapFreeSpace(page);
UnlockReleaseBuffer(buf);
- RecordPageWithFreeSpace(onerel, tblk, freespace, nblocks);
+ RecordPageWithFreeSpace(onerel, tblk, freespace);
npages++;
}
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 8522a2f51c5..0a34651581e 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -48,7 +48,6 @@
#include "replication/walsender.h"
#include "storage/condition_variable.h"
#include "storage/fd.h"
-#include "storage/freespace.h"
#include "storage/lmgr.h"
#include "storage/md.h"
#include "storage/predicate.h"
@@ -2587,12 +2586,6 @@ AbortTransaction(void)
pgstat_report_wait_end();
pgstat_progress_end_command();
- /*
- * In case we aborted during RelationGetBufferForTuple(), clear the local
- * map of heap pages.
- */
- FSMClearLocalMap();
-
/* Clean up buffer I/O and buffer context locks, too */
AbortBufferIO();
UnlockBuffers();
@@ -4880,13 +4873,6 @@ AbortSubTransaction(void)
pgstat_report_wait_end();
pgstat_progress_end_command();
-
- /*
- * In case we aborted during RelationGetBufferForTuple(), clear the local
- * map of heap pages.
- */
- FSMClearLocalMap();
-
AbortBufferIO();
UnlockBuffers();
diff --git a/src/backend/storage/freespace/README b/src/backend/storage/freespace/README
index 0d3cd29772e..e7ff23b76f7 100644
--- a/src/backend/storage/freespace/README
+++ b/src/backend/storage/freespace/README
@@ -8,41 +8,7 @@ free space to hold a tuple to be stored; or to determine that no such page
exists and the relation must be extended by one page. As of PostgreSQL 8.4
each relation has its own, extensible free space map stored in a separate
"fork" of its relation. This eliminates the disadvantages of the former
-fixed-size FSM. There are two exceptions:
-
-1. Hash indexes never have a FSM.
-2. For very small tables, a 3-page relation fork would be relatively large
-and wasteful, so to save space we refrain from creating the FSM if the
-heap has HEAP_FSM_CREATION_THRESHOLD pages or fewer.
-
-To locate free space in the latter case, we simply try pages directly without
-knowing ahead of time how much free space they have. To maintain good
-performance, we create a local in-memory map of pages to try, and only mark
-every other page as available. For example, in a 3-page heap, the local map
-would look like:
-
-ANAN
-0123
-
-Pages 0 and 2 are marked "available", and page 1 as "not available".
-Page 3 is beyond the end of the relation, so is likewise marked "not
-available". First we try page 2, and if that doesn't have sufficient free
-space we try page 0 before giving up and extending the relation. There may
-be some wasted free space on block 1, but if the relation extends to 4 pages:
-
-NANA
-0123
-
-We not only have the new page 3 at our disposal, we can now check page 1
-for free space as well.
-
-Once the FSM is created for a heap we don't remove it even if somebody deletes
-all the rows from the corresponding relation. We don't think it is a useful
-optimization as it is quite likely that relation will again grow to the same
-size.
-
-FSM data structure
-------------------
+fixed-size FSM.
It is important to keep the map small so that it can be searched rapidly.
Therefore, we don't attempt to record the exact free space on a page.
@@ -226,3 +192,5 @@ TODO
----
- fastroot to avoid traversing upper nodes with just 1 child
+- use a different system for tables that fit into one FSM page, with a
+ mechanism to switch to the real thing as it grows.
diff --git a/src/backend/storage/freespace/freespace.c b/src/backend/storage/freespace/freespace.c
index c3ed4242e2d..eee82860575 100644
--- a/src/backend/storage/freespace/freespace.c
+++ b/src/backend/storage/freespace/freespace.c
@@ -76,14 +76,6 @@
#define FSM_ROOT_LEVEL (FSM_TREE_DEPTH - 1)
#define FSM_BOTTOM_LEVEL 0
-/* Status codes for the local map. */
-
-/* Either already tried, or beyond the end of the relation */
-#define FSM_LOCAL_NOT_AVAIL 0x00
-
-/* Available to try */
-#define FSM_LOCAL_AVAIL 0x01
-
/*
* The internal FSM routines work on a logical addressing scheme. Each
* level of the tree can be thought of as a separately addressable file.
@@ -97,32 +89,6 @@ typedef struct
/* Address of the root page. */
static const FSMAddress FSM_ROOT_ADDRESS = {FSM_ROOT_LEVEL, 0};
-/*
- * For small relations, we don't create FSM to save space, instead we use
- * local in-memory map of pages to try. To locate free space, we simply try
- * pages directly without knowing ahead of time how much free space they have.
- *
- * Note that this map is used to the find the block with required free space
- * for any given relation. We clear this map when we have found a block with
- * enough free space, when we extend the relation, or on transaction abort.
- * See src/backend/storage/freespace/README for further details.
- */
-typedef struct
-{
- BlockNumber nblocks;
- uint8 map[HEAP_FSM_CREATION_THRESHOLD];
-} FSMLocalMap;
-
-static FSMLocalMap fsm_local_map =
-{
- 0,
- {
- FSM_LOCAL_NOT_AVAIL
- }
-};
-
-#define FSM_LOCAL_MAP_EXISTS (fsm_local_map.nblocks > 0)
-
/* functions to navigate the tree */
static FSMAddress fsm_get_child(FSMAddress parent, uint16 slot);
static FSMAddress fsm_get_parent(FSMAddress child, uint16 *slot);
@@ -141,14 +107,10 @@ static Size fsm_space_cat_to_avail(uint8 cat);
/* workhorse functions for various operations */
static int fsm_set_and_search(Relation rel, FSMAddress addr, uint16 slot,
uint8 newValue, uint8 minValue);
-static void fsm_local_set(Relation rel, BlockNumber cur_nblocks);
static BlockNumber fsm_search(Relation rel, uint8 min_cat);
-static BlockNumber fsm_local_search(void);
static uint8 fsm_vacuum_page(Relation rel, FSMAddress addr,
BlockNumber start, BlockNumber end,
bool *eof);
-static bool fsm_allow_writes(Relation rel, BlockNumber heapblk,
- BlockNumber nblocks, BlockNumber *get_nblocks);
/******** Public API ********/
@@ -165,46 +127,13 @@ static bool fsm_allow_writes(Relation rel, BlockNumber heapblk,
* amount of free space available on that page and then try again (see
* RecordAndGetPageWithFreeSpace). If InvalidBlockNumber is returned,
* extend the relation.
- *
- * For very small heap relations that don't have a FSM, we try every other
- * page before extending the relation. To keep track of which pages have
- * been tried, initialize a local in-memory map of pages.
*/
BlockNumber
-GetPageWithFreeSpace(Relation rel, Size spaceNeeded, bool check_fsm_only)
+GetPageWithFreeSpace(Relation rel, Size spaceNeeded)
{
uint8 min_cat = fsm_space_needed_to_cat(spaceNeeded);
- BlockNumber target_block,
- nblocks;
- /* First try the FSM, if it exists. */
- target_block = fsm_search(rel, min_cat);
-
- if (target_block == InvalidBlockNumber &&
- (rel->rd_rel->relkind == RELKIND_RELATION ||
- rel->rd_rel->relkind == RELKIND_TOASTVALUE) &&
- !check_fsm_only)
- {
- nblocks = RelationGetNumberOfBlocks(rel);
-
- if (nblocks > HEAP_FSM_CREATION_THRESHOLD)
- {
- /*
- * If the FSM knows nothing of the rel, try the last page before
- * we give up and extend. This avoids one-tuple-per-page syndrome
- * during bootstrapping or in a recently-started system.
- */
- target_block = nblocks - 1;
- }
- else if (nblocks > 0)
- {
- /* Initialize local map and get first candidate block. */
- fsm_local_set(rel, nblocks);
- target_block = fsm_local_search();
- }
- }
-
- return target_block;
+ return fsm_search(rel, min_cat);
}
/*
@@ -215,47 +144,16 @@ GetPageWithFreeSpace(Relation rel, Size spaceNeeded, bool check_fsm_only)
* also some effort to return a page close to the old page; if there's a
* page with enough free space on the same FSM page where the old one page
* is located, it is preferred.
- *
- * For very small heap relations that don't have a FSM, we update the local
- * map to indicate we have tried a page, and return the next page to try.
*/
BlockNumber
RecordAndGetPageWithFreeSpace(Relation rel, BlockNumber oldPage,
Size oldSpaceAvail, Size spaceNeeded)
{
- int old_cat;
- int search_cat;
+ int old_cat = fsm_space_avail_to_cat(oldSpaceAvail);
+ int search_cat = fsm_space_needed_to_cat(spaceNeeded);
FSMAddress addr;
uint16 slot;
int search_slot;
- BlockNumber nblocks = InvalidBlockNumber;
-
- /* First try the local map, if it exists. */
- if (FSM_LOCAL_MAP_EXISTS)
- {
- Assert((rel->rd_rel->relkind == RELKIND_RELATION ||
- rel->rd_rel->relkind == RELKIND_TOASTVALUE) &&
- fsm_local_map.map[oldPage] == FSM_LOCAL_AVAIL);
-
- fsm_local_map.map[oldPage] = FSM_LOCAL_NOT_AVAIL;
- return fsm_local_search();
- }
-
- if (!fsm_allow_writes(rel, oldPage, InvalidBlockNumber, &nblocks))
- {
- /*
- * If we have neither a local map nor a FSM, we probably just tried
- * the target block in the smgr relation entry and failed, so we'll
- * need to create the local map.
- */
- fsm_local_set(rel, nblocks);
- return fsm_local_search();
- }
-
- /* Normal FSM logic follows */
-
- old_cat = fsm_space_avail_to_cat(oldSpaceAvail);
- search_cat = fsm_space_needed_to_cat(spaceNeeded);
/* Get the location of the FSM byte representing the heap block */
addr = fsm_get_location(oldPage, &slot);
@@ -278,45 +176,21 @@ RecordAndGetPageWithFreeSpace(Relation rel, BlockNumber oldPage,
* Note that if the new spaceAvail value is higher than the old value stored
* in the FSM, the space might not become visible to searchers until the next
* FreeSpaceMapVacuum call, which updates the upper level pages.
- *
- * Callers have no need for a local map.
*/
void
-RecordPageWithFreeSpace(Relation rel, BlockNumber heapBlk,
- Size spaceAvail, BlockNumber nblocks)
+RecordPageWithFreeSpace(Relation rel, BlockNumber heapBlk, Size spaceAvail)
{
- int new_cat;
+ int new_cat = fsm_space_avail_to_cat(spaceAvail);
FSMAddress addr;
uint16 slot;
- BlockNumber dummy;
-
- if (!fsm_allow_writes(rel, heapBlk, nblocks, &dummy))
- /* No FSM to update and no local map either */
- return;
/* Get the location of the FSM byte representing the heap block */
addr = fsm_get_location(heapBlk, &slot);
- new_cat = fsm_space_avail_to_cat(spaceAvail);
fsm_set_and_search(rel, addr, slot, new_cat, 0);
}
/*
- * Clear the local map. We must call this when we have found a block with
- * enough free space, when we extend the relation, or on transaction abort.
- */
-void
-FSMClearLocalMap(void)
-{
- if (FSM_LOCAL_MAP_EXISTS)
- {
- fsm_local_map.nblocks = 0;
- memset(&fsm_local_map.map, FSM_LOCAL_NOT_AVAIL,
- sizeof(fsm_local_map.map));
- }
-}
-
-/*
* XLogRecordPageWithFreeSpace - like RecordPageWithFreeSpace, for use in
* WAL replay
*/
@@ -330,31 +204,6 @@ XLogRecordPageWithFreeSpace(RelFileNode rnode, BlockNumber heapBlk,
BlockNumber blkno;
Buffer buf;
Page page;
- bool write_to_fsm;
-
- /* This is meant to mirror the logic in fsm_allow_writes() */
- if (heapBlk >= HEAP_FSM_CREATION_THRESHOLD)
- write_to_fsm = true;
- else
- {
- /* Open the relation at smgr level */
- SMgrRelation smgr = smgropen(rnode, InvalidBackendId);
-
- if (smgrexists(smgr, FSM_FORKNUM))
- write_to_fsm = true;
- else
- {
- BlockNumber heap_nblocks = smgrnblocks(smgr, MAIN_FORKNUM);
-
- if (heap_nblocks > HEAP_FSM_CREATION_THRESHOLD)
- write_to_fsm = true;
- else
- write_to_fsm = false;
- }
- }
-
- if (!write_to_fsm)
- return;
/* Get the location of the FSM byte representing the heap block */
addr = fsm_get_location(heapBlk, &slot);
@@ -1055,141 +904,3 @@ fsm_vacuum_page(Relation rel, FSMAddress addr,
return max_avail;
}
-
-/*
- * For heaps, we prevent creation of the FSM unless the number of pages
- * exceeds HEAP_FSM_CREATION_THRESHOLD. For tables that don't already have
- * a FSM, this will save an inode and a few kB of space.
- *
- * XXX The API is a little awkward -- if the caller passes a valid nblocks
- * value, it can avoid invoking a system call. If the caller passes
- * InvalidBlockNumber and receives a false return value, it can get an
- * up-to-date relation size from get_nblocks. This saves a few cycles in
- * the caller, which would otherwise need to get the relation size by itself.
- */
-static bool
-fsm_allow_writes(Relation rel, BlockNumber heapblk,
- BlockNumber nblocks, BlockNumber *get_nblocks)
-{
- bool skip_get_nblocks;
-
- if (heapblk >= HEAP_FSM_CREATION_THRESHOLD)
- return true;
-
- /* Non-heap rels can always create a FSM. */
- if (rel->rd_rel->relkind != RELKIND_RELATION &&
- rel->rd_rel->relkind != RELKIND_TOASTVALUE)
- return true;
-
- /*
- * If the caller knows nblocks, we can avoid a system call later. If it
- * doesn't, maybe we have relpages from a previous VACUUM. Since the table
- * may have extended since then, we still have to count the pages later if
- * we can't return now.
- */
- if (nblocks != InvalidBlockNumber)
- {
- if (nblocks > HEAP_FSM_CREATION_THRESHOLD)
- return true;
- else
- skip_get_nblocks = true;
- }
- else
- {
- if (rel->rd_rel->relpages != InvalidBlockNumber &&
- rel->rd_rel->relpages > HEAP_FSM_CREATION_THRESHOLD)
- return true;
- else
- skip_get_nblocks = false;
- }
-
- RelationOpenSmgr(rel);
- if (smgrexists(rel->rd_smgr, FSM_FORKNUM))
- return true;
-
- if (skip_get_nblocks)
- return false;
-
- /* last resort */
- *get_nblocks = RelationGetNumberOfBlocks(rel);
- if (*get_nblocks > HEAP_FSM_CREATION_THRESHOLD)
- return true;
- else
- return false;
-}
-
-/*
- * Initialize the local map of blocks to try, for when there is no FSM.
- *
- * When we initialize the map, the whole heap is potentially available to
- * try. Testing revealed that trying every block can cause a small
- * performance dip compared to when we use a FSM, so we try every other
- * block instead.
- */
-static void
-fsm_local_set(Relation rel, BlockNumber cur_nblocks)
-{
- BlockNumber blkno,
- cached_target_block;
-
- /* The local map must not be set already. */
- Assert(!FSM_LOCAL_MAP_EXISTS);
-
- /*
- * Starting at the current last block in the relation and working
- * backwards, mark alternating blocks as available.
- */
- blkno = cur_nblocks - 1;
- while (true)
- {
- fsm_local_map.map[blkno] = FSM_LOCAL_AVAIL;
- if (blkno >= 2)
- blkno -= 2;
- else
- break;
- }
-
- /* Cache the number of blocks. */
- fsm_local_map.nblocks = cur_nblocks;
-
- /* Set the status of the cached target block to 'unavailable'. */
- cached_target_block = RelationGetTargetBlock(rel);
- if (cached_target_block != InvalidBlockNumber &&
- cached_target_block < cur_nblocks)
- fsm_local_map.map[cached_target_block] = FSM_LOCAL_NOT_AVAIL;
-}
-
-/*
- * Search the local map for an available block to try, in descending order.
- * As such, there is no heuristic available to decide which order will be
- * better to try, but the probability of having space in the last block in the
- * map is higher because that is the most recent block added to the heap.
- *
- * This function is used when there is no FSM.
- */
-static BlockNumber
-fsm_local_search(void)
-{
- BlockNumber target_block;
-
- /* Local map must be set by now. */
- Assert(FSM_LOCAL_MAP_EXISTS);
-
- target_block = fsm_local_map.nblocks;
- do
- {
- target_block--;
- if (fsm_local_map.map[target_block] == FSM_LOCAL_AVAIL)
- return target_block;
- } while (target_block > 0);
-
- /*
- * If we didn't find any available block to try in the local map, then
- * clear it. This prevents us from using the map again without setting it
- * first, which would otherwise lead to the same conclusion again and
- * again.
- */
- FSMClearLocalMap();
-
- return InvalidBlockNumber;
-}
diff --git a/src/backend/storage/freespace/indexfsm.c b/src/backend/storage/freespace/indexfsm.c
index 9d8f43d3739..58cedeaa9f7 100644
--- a/src/backend/storage/freespace/indexfsm.c
+++ b/src/backend/storage/freespace/indexfsm.c
@@ -37,7 +37,7 @@
BlockNumber
GetFreeIndexPage(Relation rel)
{
- BlockNumber blkno = GetPageWithFreeSpace(rel, BLCKSZ / 2, true);
+ BlockNumber blkno = GetPageWithFreeSpace(rel, BLCKSZ / 2);
if (blkno != InvalidBlockNumber)
RecordUsedIndexPage(rel, blkno);
@@ -51,7 +51,7 @@ GetFreeIndexPage(Relation rel)
void
RecordFreeIndexPage(Relation rel, BlockNumber freeBlock)
{
- RecordPageWithFreeSpace(rel, freeBlock, BLCKSZ - 1, InvalidBlockNumber);
+ RecordPageWithFreeSpace(rel, freeBlock, BLCKSZ - 1);
}
@@ -61,7 +61,7 @@ RecordFreeIndexPage(Relation rel, BlockNumber freeBlock)
void
RecordUsedIndexPage(Relation rel, BlockNumber usedBlock)
{
- RecordPageWithFreeSpace(rel, usedBlock, 0, InvalidBlockNumber);
+ RecordPageWithFreeSpace(rel, usedBlock, 0);
}
/*
diff --git a/src/bin/pg_upgrade/info.c b/src/bin/pg_upgrade/info.c
index 902bfc647e9..2f925f086c3 100644
--- a/src/bin/pg_upgrade/info.c
+++ b/src/bin/pg_upgrade/info.c
@@ -200,8 +200,6 @@ create_rel_filename_map(const char *old_data, const char *new_data,
map->old_db_oid = old_db->db_oid;
map->new_db_oid = new_db->db_oid;
- map->relpages = old_rel->relpages;
- map->relkind = old_rel->relkind;
/*
* old_relfilenode might differ from pg_class.oid (and hence
@@ -420,7 +418,6 @@ get_rel_infos(ClusterInfo *cluster, DbInfo *dbinfo)
char *nspname = NULL;
char *relname = NULL;
char *tablespace = NULL;
- char *relkind = NULL;
int i_spclocation,
i_nspname,
i_relname,
@@ -428,9 +425,7 @@ get_rel_infos(ClusterInfo *cluster, DbInfo *dbinfo)
i_indtable,
i_toastheap,
i_relfilenode,
- i_reltablespace,
- i_relpages,
- i_relkind;
+ i_reltablespace;
char query[QUERY_ALLOC];
char *last_namespace = NULL,
*last_tablespace = NULL;
@@ -499,7 +494,7 @@ get_rel_infos(ClusterInfo *cluster, DbInfo *dbinfo)
*/
snprintf(query + strlen(query), sizeof(query) - strlen(query),
"SELECT all_rels.*, n.nspname, c.relname, "
- " c.relfilenode, c.reltablespace, c.relpages, c.relkind, %s "
+ " c.relfilenode, c.reltablespace, %s "
"FROM (SELECT * FROM regular_heap "
" UNION ALL "
" SELECT * FROM toast_heap "
@@ -530,8 +525,6 @@ get_rel_infos(ClusterInfo *cluster, DbInfo *dbinfo)
i_relname = PQfnumber(res, "relname");
i_relfilenode = PQfnumber(res, "relfilenode");
i_reltablespace = PQfnumber(res, "reltablespace");
- i_relpages = PQfnumber(res, "relpages");
- i_relkind = PQfnumber(res, "relkind");
i_spclocation = PQfnumber(res, "spclocation");
for (relnum = 0; relnum < ntups; relnum++)
@@ -563,11 +556,6 @@ get_rel_infos(ClusterInfo *cluster, DbInfo *dbinfo)
curr->relname = pg_strdup(relname);
curr->relfilenode = atooid(PQgetvalue(res, relnum, i_relfilenode));
- curr->relpages = atoi(PQgetvalue(res, relnum, i_relpages));
-
- relkind = PQgetvalue(res, relnum, i_relkind);
- curr->relkind = relkind[0];
-
curr->tblsp_alloc = false;
/* Is the tablespace oid non-default? */
diff --git a/src/bin/pg_upgrade/pg_upgrade.h b/src/bin/pg_upgrade/pg_upgrade.h
index baeb8ff0f85..2f67eee22b8 100644
--- a/src/bin/pg_upgrade/pg_upgrade.h
+++ b/src/bin/pg_upgrade/pg_upgrade.h
@@ -147,8 +147,6 @@ typedef struct
char *tablespace; /* tablespace path; "" for cluster default */
bool nsp_alloc; /* should nspname be freed? */
bool tblsp_alloc; /* should tablespace be freed? */
- int32 relpages; /* # of pages -- see pg_class.h */
- char relkind; /* relation kind -- see pg_class.h */
} RelInfo;
typedef struct
@@ -175,10 +173,6 @@ typedef struct
*/
Oid old_relfilenode;
Oid new_relfilenode;
-
- int32 relpages; /* # of pages -- see pg_class.h */
- char relkind; /* relation kind -- see pg_class.h */
-
/* the rest are used only for logging and error reporting */
char *nspname; /* namespaces */
char *relname;
diff --git a/src/bin/pg_upgrade/relfilenode.c b/src/bin/pg_upgrade/relfilenode.c
index dd3c8cefe42..0c78073f0eb 100644
--- a/src/bin/pg_upgrade/relfilenode.c
+++ b/src/bin/pg_upgrade/relfilenode.c
@@ -14,12 +14,10 @@
#include <sys/stat.h>
#include "catalog/pg_class_d.h"
#include "access/transam.h"
-#include "storage/freespace.h"
static void transfer_single_new_db(FileNameMap *maps, int size, char *old_tablespace);
static void transfer_relfile(FileNameMap *map, const char *suffix, bool vm_must_add_frozenbit);
-static bool new_cluster_needs_fsm(FileNameMap *map);
/*
@@ -176,8 +174,7 @@ transfer_single_new_db(FileNameMap *maps, int size, char *old_tablespace)
/*
* Copy/link any fsm and vm files, if they exist
*/
- if (new_cluster_needs_fsm(&maps[mapnum]))
- transfer_relfile(&maps[mapnum], "_fsm", vm_must_add_frozenbit);
+ transfer_relfile(&maps[mapnum], "_fsm", vm_must_add_frozenbit);
if (vm_crashsafe_match)
transfer_relfile(&maps[mapnum], "_vm", vm_must_add_frozenbit);
}
@@ -281,61 +278,3 @@ transfer_relfile(FileNameMap *map, const char *type_suffix, bool vm_must_add_fro
}
}
}
-
-/*
- * new_cluster_needs_fsm()
- *
- * Return false for small heaps if we're upgrading across PG 12, the first
- * version where small heap relations don't have FSMs by default.
- */
-static bool
-new_cluster_needs_fsm(FileNameMap *map)
-{
- char old_primary_file[MAXPGPATH];
- struct stat statbuf;
-
- /* fsm/vm files added in PG 8.4 */
- Assert(GET_MAJOR_VERSION(old_cluster.major_version) >= 804);
-
- if (!(GET_MAJOR_VERSION(old_cluster.major_version) <= 1100 &&
- GET_MAJOR_VERSION(new_cluster.major_version) >= 1200))
- return true;
-
- /* Always transfer FSMs of non-heap relations. */
- if (map->relkind != RELKIND_RELATION &&
- map->relkind != RELKIND_TOASTVALUE)
- return true;
-
- /*
- * If pg_class.relpages falsely reports that the heap is above the
- * threshold, we will transfer a FSM when we don't need to, but this is
- * harmless.
- */
- if (map->relpages > HEAP_FSM_CREATION_THRESHOLD)
- return true;
-
- /* Determine path of the primary file. */
- snprintf(old_primary_file, sizeof(old_primary_file), "%s%s/%u/%u",
- map->old_tablespace,
- map->old_tablespace_suffix,
- map->old_db_oid,
- map->old_relfilenode);
-
- /*
- * If pg_class.relpages falsely reports that the heap is below the
- * threshold, a FSM would be skipped when we actually need it. To guard
- * against this, we verify the size of the primary file.
- */
- if (stat(old_primary_file, &statbuf) != 0)
- {
- pg_fatal("error while checking for file existence \"%s.%s\" (\"%s\"): %s\n",
- map->nspname, map->relname, old_primary_file, strerror(errno));
-
- /* Keep compiler quiet. */
- return false;
- }
- else if (statbuf.st_size > HEAP_FSM_CREATION_THRESHOLD * BLCKSZ)
- return true;
- else
- return false;
-}
diff --git a/src/include/storage/freespace.h b/src/include/storage/freespace.h
index dbaae651c58..8b000334382 100644
--- a/src/include/storage/freespace.h
+++ b/src/include/storage/freespace.h
@@ -18,20 +18,15 @@
#include "storage/relfilenode.h"
#include "utils/relcache.h"
-/* Only create the FSM if the heap has greater than this many blocks */
-#define HEAP_FSM_CREATION_THRESHOLD 4
-
/* prototypes for public functions in freespace.c */
extern Size GetRecordedFreeSpace(Relation rel, BlockNumber heapBlk);
-extern BlockNumber GetPageWithFreeSpace(Relation rel, Size spaceNeeded,
- bool check_fsm_only);
+extern BlockNumber GetPageWithFreeSpace(Relation rel, Size spaceNeeded);
extern BlockNumber RecordAndGetPageWithFreeSpace(Relation rel,
BlockNumber oldPage,
Size oldSpaceAvail,
Size spaceNeeded);
extern void RecordPageWithFreeSpace(Relation rel, BlockNumber heapBlk,
- Size spaceAvail, BlockNumber nblocks);
-extern void FSMClearLocalMap(void);
+ Size spaceAvail);
extern void XLogRecordPageWithFreeSpace(RelFileNode rnode, BlockNumber heapBlk,
Size spaceAvail);
diff --git a/src/test/regress/expected/fsm.out b/src/test/regress/expected/fsm.out
deleted file mode 100644
index 698d4b0be56..00000000000
--- a/src/test/regress/expected/fsm.out
+++ /dev/null
@@ -1,73 +0,0 @@
---
--- Free Space Map test
---
-SELECT current_setting('block_size')::integer AS blocksize,
-current_setting('block_size')::integer / 8 AS strsize
-\gset
-CREATE TABLE fsm_check_size (num int, str text);
--- Fill 3 blocks with one record each
-ALTER TABLE fsm_check_size SET (fillfactor=15);
-INSERT INTO fsm_check_size SELECT i, rpad('', :strsize, 'a')
-FROM generate_series(1,3) i;
--- There should be no FSM
-VACUUM fsm_check_size;
-SELECT pg_relation_size('fsm_check_size', 'main') / :blocksize AS heap_nblocks,
-pg_relation_size('fsm_check_size', 'fsm') / :blocksize AS fsm_nblocks;
- heap_nblocks | fsm_nblocks
---------------+-------------
- 3 | 0
-(1 row)
-
--- The following operations are for testing the functionality of the local
--- in-memory map. In particular, we want to be able to insert into some
--- other block than the one at the end of the heap, without using a FSM.
--- Fill most of the last block
-ALTER TABLE fsm_check_size SET (fillfactor=100);
-INSERT INTO fsm_check_size SELECT i, rpad('', :strsize, 'a')
-FROM generate_series(101,105) i;
--- Make sure records can go into any block but the last one
-ALTER TABLE fsm_check_size SET (fillfactor=30);
--- Insert large record and make sure it does not cause the relation to extend
-INSERT INTO fsm_check_size VALUES (111, rpad('', :strsize, 'a'));
-VACUUM fsm_check_size;
-SELECT pg_relation_size('fsm_check_size', 'main') / :blocksize AS heap_nblocks,
-pg_relation_size('fsm_check_size', 'fsm') / :blocksize AS fsm_nblocks;
- heap_nblocks | fsm_nblocks
---------------+-------------
- 3 | 0
-(1 row)
-
--- Extend table with enough blocks to exceed the FSM threshold
-DO $$
-DECLARE curtid tid;
-num int;
-BEGIN
-num = 11;
- LOOP
- INSERT INTO fsm_check_size VALUES (num, 'b') RETURNING ctid INTO curtid;
- EXIT WHEN curtid >= tid '(4, 0)';
- num = num + 1;
- END LOOP;
-END;
-$$;
-VACUUM fsm_check_size;
-SELECT pg_relation_size('fsm_check_size', 'fsm') / :blocksize AS fsm_nblocks;
- fsm_nblocks
--------------
- 3
-(1 row)
-
--- Add long random string to extend TOAST table to 1 block
-INSERT INTO fsm_check_size
-VALUES(0, (SELECT string_agg(md5(chr(i)), '')
- FROM generate_series(1, :blocksize / 100) i));
-VACUUM fsm_check_size;
-SELECT pg_relation_size(reltoastrelid, 'main') / :blocksize AS toast_nblocks,
-pg_relation_size(reltoastrelid, 'fsm') / :blocksize AS toast_fsm_nblocks
-FROM pg_class WHERE relname = 'fsm_check_size';
- toast_nblocks | toast_fsm_nblocks
----------------+-------------------
- 1 | 0
-(1 row)
-
-DROP TABLE fsm_check_size;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 3b7759b6faa..312b7c22c50 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -20,7 +20,7 @@ test: boolean char name varchar text int2 int4 int8 oid float4 float8 bit numeri
# strings depends on char, varchar and text
# numerology depends on int2, int4, int8, float4, float8
# ----------
-test: strings numerology point lseg line box path polygon circle date time timetz timestamp timestamptz interval inet macaddr macaddr8 tstypes fsm
+test: strings numerology point lseg line box path polygon circle date time timetz timestamp timestamptz interval inet macaddr macaddr8 tstypes
# ----------
# Another group of parallel tests
diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule
index 43523c6fc62..9d44c313298 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -40,7 +40,6 @@ test: inet
test: macaddr
test: macaddr8
test: tstypes
-test: fsm
test: geometry
test: horology
test: regex
diff --git a/src/test/regress/sql/fsm.sql b/src/test/regress/sql/fsm.sql
deleted file mode 100644
index 7295e0439b2..00000000000
--- a/src/test/regress/sql/fsm.sql
+++ /dev/null
@@ -1,66 +0,0 @@
---
--- Free Space Map test
---
-SELECT current_setting('block_size')::integer AS blocksize,
-current_setting('block_size')::integer / 8 AS strsize
-\gset
-
-CREATE TABLE fsm_check_size (num int, str text);
-
--- Fill 3 blocks with one record each
-ALTER TABLE fsm_check_size SET (fillfactor=15);
-INSERT INTO fsm_check_size SELECT i, rpad('', :strsize, 'a')
-FROM generate_series(1,3) i;
-
--- There should be no FSM
-VACUUM fsm_check_size;
-SELECT pg_relation_size('fsm_check_size', 'main') / :blocksize AS heap_nblocks,
-pg_relation_size('fsm_check_size', 'fsm') / :blocksize AS fsm_nblocks;
-
--- The following operations are for testing the functionality of the local
--- in-memory map. In particular, we want to be able to insert into some
--- other block than the one at the end of the heap, without using a FSM.
-
--- Fill most of the last block
-ALTER TABLE fsm_check_size SET (fillfactor=100);
-INSERT INTO fsm_check_size SELECT i, rpad('', :strsize, 'a')
-FROM generate_series(101,105) i;
-
--- Make sure records can go into any block but the last one
-ALTER TABLE fsm_check_size SET (fillfactor=30);
-
--- Insert large record and make sure it does not cause the relation to extend
-INSERT INTO fsm_check_size VALUES (111, rpad('', :strsize, 'a'));
-
-VACUUM fsm_check_size;
-SELECT pg_relation_size('fsm_check_size', 'main') / :blocksize AS heap_nblocks,
-pg_relation_size('fsm_check_size', 'fsm') / :blocksize AS fsm_nblocks;
-
--- Extend table with enough blocks to exceed the FSM threshold
-DO $$
-DECLARE curtid tid;
-num int;
-BEGIN
-num = 11;
- LOOP
- INSERT INTO fsm_check_size VALUES (num, 'b') RETURNING ctid INTO curtid;
- EXIT WHEN curtid >= tid '(4, 0)';
- num = num + 1;
- END LOOP;
-END;
-$$;
-
-VACUUM fsm_check_size;
-SELECT pg_relation_size('fsm_check_size', 'fsm') / :blocksize AS fsm_nblocks;
-
--- Add long random string to extend TOAST table to 1 block
-INSERT INTO fsm_check_size
-VALUES(0, (SELECT string_agg(md5(chr(i)), '')
- FROM generate_series(1, :blocksize / 100) i));
-
-VACUUM fsm_check_size;
-SELECT pg_relation_size(reltoastrelid, 'main') / :blocksize AS toast_nblocks,
-pg_relation_size(reltoastrelid, 'fsm') / :blocksize AS toast_fsm_nblocks
-FROM pg_class WHERE relname = 'fsm_check_size';
-
-DROP TABLE fsm_check_size;