Commit 9e936693 authored by Tom Lane's avatar Tom Lane

Fix free space map to correctly track the total amount of FSM space needed

even when a single relation requires more than max_fsm_pages pages.  Also,
make VACUUM emit a warning in this case, since it likely means that VACUUM
FULL or other drastic corrective measure is needed.  Per reports from Jeff
Frost and others of unexpected changes in the claimed max_fsm_pages need.
parent b0d64a09
...@@ -36,19 +36,19 @@ Notes ...@@ -36,19 +36,19 @@ Notes
pg_freespacemap_relations pg_freespacemap_relations
Column | references | Description Column | references | Description
----------------+----------------------+------------------------------------ ------------------+----------------------+----------------------------------
reltablespace | pg_tablespace.oid | Tablespace oid of the relation. reltablespace | pg_tablespace.oid | Tablespace oid of the relation.
reldatabase | pg_database.oid | Database oid of the relation. reldatabase | pg_database.oid | Database oid of the relation.
relfilenode | pg_class.relfilenode | Relfilenode of the relation. relfilenode | pg_class.relfilenode | Relfilenode of the relation.
avgrequest | | Moving average of free space avgrequest | | Moving average of free space
| | requests (NULL for indexes) | | requests (NULL for indexes)
lastpagecount | | Count of pages last reported as interestingpages | | Count of pages last reported as
| | containing useful free space. | | containing useful free space.
storedpages | | Count of pages actually stored storedpages | | Count of pages actually stored
| | in free space map. | | in free space map.
nextpage | | Page index (from 0) to start next nextpage | | Page index (from 0) to start next
| | search at. | | search at.
pg_freespacemap_pages pg_freespacemap_pages
...@@ -65,11 +65,11 @@ Notes ...@@ -65,11 +65,11 @@ Notes
For pg_freespacemap_relations, there is one row for each relation in the free For pg_freespacemap_relations, there is one row for each relation in the free
space map. storedpages is the number of pages actually stored in the map, space map. storedpages is the number of pages actually stored in the map,
while lastpagecount is the number of pages VACUUM last tried to store while interestingpages is the number of pages the last VACUUM thought had
(ie, the number that VACUUM thought had useful amounts of free space). useful amounts of free space.
If storedpages is consistently less than lastpagecount then it'd be a good If storedpages is consistently less than interestingpages then it'd be a
idea to increase max_fsm_pages. Also, if the number of rows in good idea to increase max_fsm_pages. Also, if the number of rows in
pg_freespacemap_relations is close to max_fsm_relations, then you should pg_freespacemap_relations is close to max_fsm_relations, then you should
consider increasing max_fsm_relations. consider increasing max_fsm_relations.
...@@ -96,36 +96,36 @@ Sample output - pg_freespacemap_relations ...@@ -96,36 +96,36 @@ Sample output - pg_freespacemap_relations
regression=# \d pg_freespacemap_relations regression=# \d pg_freespacemap_relations
View "public.pg_freespacemap_relations" View "public.pg_freespacemap_relations"
Column | Type | Modifiers Column | Type | Modifiers
---------------+---------+----------- ------------------+---------+-----------
reltablespace | oid | reltablespace | oid |
reldatabase | oid | reldatabase | oid |
relfilenode | oid | relfilenode | oid |
avgrequest | integer | avgrequest | integer |
lastpagecount | integer | interestingpages | integer |
storedpages | integer | storedpages | integer |
nextpage | integer | nextpage | integer |
View definition: View definition:
SELECT p.reltablespace, p.reldatabase, p.relfilenode, p.avgrequest, p.lastpagecount, p.storedpages, p.nextpage SELECT p.reltablespace, p.reldatabase, p.relfilenode, p.avgrequest, p.interestingpages, p.storedpages, p.nextpage
FROM pg_freespacemap_relations() p(reltablespace oid, reldatabase oid, relfilenode oid, avgrequest integer, lastpagecount integer, storedpages integer, nextpage integer); FROM pg_freespacemap_relations() p(reltablespace oid, reldatabase oid, relfilenode oid, avgrequest integer, interestingpages integer, storedpages integer, nextpage integer);
regression=# SELECT c.relname, r.avgrequest, r.lastpagecount, r.storedpages regression=# SELECT c.relname, r.avgrequest, r.interestingpages, r.storedpages
FROM pg_freespacemap_relations r INNER JOIN pg_class c FROM pg_freespacemap_relations r INNER JOIN pg_class c
ON c.relfilenode = r.relfilenode INNER JOIN pg_database d ON c.relfilenode = r.relfilenode INNER JOIN pg_database d
ON r.reldatabase = d.oid AND (d.datname = current_database()) ON r.reldatabase = d.oid AND (d.datname = current_database())
ORDER BY r.storedpages DESC LIMIT 10; ORDER BY r.storedpages DESC LIMIT 10;
relname | avgrequest | lastpagecount | storedpages relname | avgrequest | interestingpages | storedpages
---------------------------------+------------+---------------+------------- ---------------------------------+------------+------------------+-------------
onek | 256 | 109 | 109 onek | 256 | 109 | 109
pg_attribute | 167 | 93 | 93 pg_attribute | 167 | 93 | 93
pg_class | 191 | 49 | 49 pg_class | 191 | 49 | 49
pg_attribute_relid_attnam_index | | 48 | 48 pg_attribute_relid_attnam_index | | 48 | 48
onek2 | 256 | 37 | 37 onek2 | 256 | 37 | 37
pg_depend | 95 | 26 | 26 pg_depend | 95 | 26 | 26
pg_type | 199 | 16 | 16 pg_type | 199 | 16 | 16
pg_rewrite | 1011 | 13 | 13 pg_rewrite | 1011 | 13 | 13
pg_class_relname_nsp_index | | 10 | 10 pg_class_relname_nsp_index | | 10 | 10
pg_proc | 302 | 8 | 8 pg_proc | 302 | 8 | 8
(10 rows) (10 rows)
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* pg_freespacemap.c * pg_freespacemap.c
* display some contents of the free space relation and page maps. * display some contents of the free space relation and page maps.
* *
* $PostgreSQL: pgsql/contrib/pg_freespacemap/pg_freespacemap.c,v 1.6 2006/05/30 22:12:13 tgl Exp $ * $PostgreSQL: pgsql/contrib/pg_freespacemap/pg_freespacemap.c,v 1.7 2006/09/21 20:31:21 tgl Exp $
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#include "postgres.h" #include "postgres.h"
...@@ -53,7 +53,7 @@ typedef struct ...@@ -53,7 +53,7 @@ typedef struct
Oid reldatabase; Oid reldatabase;
Oid relfilenode; Oid relfilenode;
Size avgrequest; Size avgrequest;
int lastpagecount; BlockNumber interestingpages;
int storedpages; int storedpages;
int nextpage; int nextpage;
bool isindex; bool isindex;
...@@ -303,7 +303,7 @@ pg_freespacemap_relations(PG_FUNCTION_ARGS) ...@@ -303,7 +303,7 @@ pg_freespacemap_relations(PG_FUNCTION_ARGS)
OIDOID, -1, 0); OIDOID, -1, 0);
TupleDescInitEntry(tupledesc, (AttrNumber) 4, "avgrequest", TupleDescInitEntry(tupledesc, (AttrNumber) 4, "avgrequest",
INT4OID, -1, 0); INT4OID, -1, 0);
TupleDescInitEntry(tupledesc, (AttrNumber) 5, "lastpagecount", TupleDescInitEntry(tupledesc, (AttrNumber) 5, "interestingpages",
INT4OID, -1, 0); INT4OID, -1, 0);
TupleDescInitEntry(tupledesc, (AttrNumber) 6, "storedpages", TupleDescInitEntry(tupledesc, (AttrNumber) 6, "storedpages",
INT4OID, -1, 0); INT4OID, -1, 0);
...@@ -334,7 +334,7 @@ pg_freespacemap_relations(PG_FUNCTION_ARGS) ...@@ -334,7 +334,7 @@ pg_freespacemap_relations(PG_FUNCTION_ARGS)
fctx->record[i].reldatabase = fsmrel->key.dbNode; fctx->record[i].reldatabase = fsmrel->key.dbNode;
fctx->record[i].relfilenode = fsmrel->key.relNode; fctx->record[i].relfilenode = fsmrel->key.relNode;
fctx->record[i].avgrequest = (int64)fsmrel->avgRequest; fctx->record[i].avgrequest = (int64)fsmrel->avgRequest;
fctx->record[i].lastpagecount = fsmrel->lastPageCount; fctx->record[i].interestingpages = fsmrel->interestingPages;
fctx->record[i].storedpages = fsmrel->storedPages; fctx->record[i].storedpages = fsmrel->storedPages;
fctx->record[i].nextpage = fsmrel->nextPage; fctx->record[i].nextpage = fsmrel->nextPage;
fctx->record[i].isindex = fsmrel->isIndex; fctx->record[i].isindex = fsmrel->isIndex;
...@@ -380,7 +380,7 @@ pg_freespacemap_relations(PG_FUNCTION_ARGS) ...@@ -380,7 +380,7 @@ pg_freespacemap_relations(PG_FUNCTION_ARGS)
values[3] = UInt32GetDatum(record->avgrequest); values[3] = UInt32GetDatum(record->avgrequest);
nulls[3] = false; nulls[3] = false;
} }
values[4] = Int32GetDatum(record->lastpagecount); values[4] = Int32GetDatum(record->interestingpages);
nulls[4] = false; nulls[4] = false;
values[5] = Int32GetDatum(record->storedpages); values[5] = Int32GetDatum(record->storedpages);
nulls[5] = false; nulls[5] = false;
......
...@@ -30,7 +30,7 @@ CREATE VIEW pg_freespacemap_relations AS ...@@ -30,7 +30,7 @@ CREATE VIEW pg_freespacemap_relations AS
reldatabase oid, reldatabase oid,
relfilenode oid, relfilenode oid,
avgrequest integer, avgrequest integer,
lastpagecount integer, interestingpages integer,
storedpages integer, storedpages integer,
nextpage integer); nextpage integer);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gin/ginvacuum.c,v 1.5 2006/07/31 20:08:59 tgl Exp $ * $PostgreSQL: pgsql/src/backend/access/gin/ginvacuum.c,v 1.6 2006/09/21 20:31:21 tgl Exp $
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -575,7 +575,8 @@ ginvacuumcleanup(PG_FUNCTION_ARGS) { ...@@ -575,7 +575,8 @@ ginvacuumcleanup(PG_FUNCTION_ARGS) {
bool needLock; bool needLock;
BlockNumber npages, BlockNumber npages,
blkno; blkno;
BlockNumber nFreePages, BlockNumber totFreePages,
nFreePages,
*freePages, *freePages,
maxFreePages; maxFreePages;
BlockNumber lastBlock = GIN_ROOT_BLKNO, BlockNumber lastBlock = GIN_ROOT_BLKNO,
...@@ -610,7 +611,7 @@ ginvacuumcleanup(PG_FUNCTION_ARGS) { ...@@ -610,7 +611,7 @@ ginvacuumcleanup(PG_FUNCTION_ARGS) {
if (maxFreePages > MaxFSMPages) if (maxFreePages > MaxFSMPages)
maxFreePages = MaxFSMPages; maxFreePages = MaxFSMPages;
nFreePages = 0; totFreePages = nFreePages = 0;
freePages = (BlockNumber *) palloc(sizeof(BlockNumber) * maxFreePages); freePages = (BlockNumber *) palloc(sizeof(BlockNumber) * maxFreePages);
for (blkno = GIN_ROOT_BLKNO + 1; blkno < npages; blkno++) { for (blkno = GIN_ROOT_BLKNO + 1; blkno < npages; blkno++) {
...@@ -626,6 +627,7 @@ ginvacuumcleanup(PG_FUNCTION_ARGS) { ...@@ -626,6 +627,7 @@ ginvacuumcleanup(PG_FUNCTION_ARGS) {
if ( GinPageIsDeleted(page) ) { if ( GinPageIsDeleted(page) ) {
if (nFreePages < maxFreePages) if (nFreePages < maxFreePages)
freePages[nFreePages++] = blkno; freePages[nFreePages++] = blkno;
totFreePages++;
} else } else
lastFilledBlock = blkno; lastFilledBlock = blkno;
...@@ -638,7 +640,7 @@ ginvacuumcleanup(PG_FUNCTION_ARGS) { ...@@ -638,7 +640,7 @@ ginvacuumcleanup(PG_FUNCTION_ARGS) {
int i; int i;
for (i = 0; i < nFreePages; i++) for (i = 0; i < nFreePages; i++)
if (freePages[i] >= lastFilledBlock) { if (freePages[i] >= lastFilledBlock) {
nFreePages = i; totFreePages = nFreePages = i;
break; break;
} }
...@@ -648,8 +650,8 @@ ginvacuumcleanup(PG_FUNCTION_ARGS) { ...@@ -648,8 +650,8 @@ ginvacuumcleanup(PG_FUNCTION_ARGS) {
stats->pages_removed = lastBlock - lastFilledBlock; stats->pages_removed = lastBlock - lastFilledBlock;
} }
RecordIndexFreeSpace(&index->rd_node, nFreePages, freePages); RecordIndexFreeSpace(&index->rd_node, totFreePages, nFreePages, freePages);
stats->pages_free = nFreePages; stats->pages_free = totFreePages;
if (needLock) if (needLock)
LockRelationForExtension(index, ExclusiveLock); LockRelationForExtension(index, ExclusiveLock);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gist/gistvacuum.c,v 1.26 2006/07/31 20:08:59 tgl Exp $ * $PostgreSQL: pgsql/src/backend/access/gist/gistvacuum.c,v 1.27 2006/09/21 20:31:21 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -491,7 +491,8 @@ gistvacuumcleanup(PG_FUNCTION_ARGS) ...@@ -491,7 +491,8 @@ gistvacuumcleanup(PG_FUNCTION_ARGS)
Relation rel = info->index; Relation rel = info->index;
BlockNumber npages, BlockNumber npages,
blkno; blkno;
BlockNumber nFreePages, BlockNumber totFreePages,
nFreePages,
*freePages, *freePages,
maxFreePages; maxFreePages;
BlockNumber lastBlock = GIST_ROOT_BLKNO, BlockNumber lastBlock = GIST_ROOT_BLKNO,
...@@ -563,8 +564,9 @@ gistvacuumcleanup(PG_FUNCTION_ARGS) ...@@ -563,8 +564,9 @@ gistvacuumcleanup(PG_FUNCTION_ARGS)
if (maxFreePages > MaxFSMPages) if (maxFreePages > MaxFSMPages)
maxFreePages = MaxFSMPages; maxFreePages = MaxFSMPages;
nFreePages = 0; totFreePages = nFreePages = 0;
freePages = (BlockNumber *) palloc(sizeof(BlockNumber) * maxFreePages); freePages = (BlockNumber *) palloc(sizeof(BlockNumber) * maxFreePages);
for (blkno = GIST_ROOT_BLKNO + 1; blkno < npages; blkno++) for (blkno = GIST_ROOT_BLKNO + 1; blkno < npages; blkno++)
{ {
Buffer buffer; Buffer buffer;
...@@ -579,10 +581,8 @@ gistvacuumcleanup(PG_FUNCTION_ARGS) ...@@ -579,10 +581,8 @@ gistvacuumcleanup(PG_FUNCTION_ARGS)
if (PageIsNew(page) || GistPageIsDeleted(page)) if (PageIsNew(page) || GistPageIsDeleted(page))
{ {
if (nFreePages < maxFreePages) if (nFreePages < maxFreePages)
{ freePages[nFreePages++] = blkno;
freePages[nFreePages] = blkno; totFreePages++;
nFreePages++;
}
} }
else else
lastFilledBlock = blkno; lastFilledBlock = blkno;
...@@ -597,7 +597,7 @@ gistvacuumcleanup(PG_FUNCTION_ARGS) ...@@ -597,7 +597,7 @@ gistvacuumcleanup(PG_FUNCTION_ARGS)
for (i = 0; i < nFreePages; i++) for (i = 0; i < nFreePages; i++)
if (freePages[i] >= lastFilledBlock) if (freePages[i] >= lastFilledBlock)
{ {
nFreePages = i; totFreePages = nFreePages = i;
break; break;
} }
...@@ -606,11 +606,11 @@ gistvacuumcleanup(PG_FUNCTION_ARGS) ...@@ -606,11 +606,11 @@ gistvacuumcleanup(PG_FUNCTION_ARGS)
stats->std.pages_removed = lastBlock - lastFilledBlock; stats->std.pages_removed = lastBlock - lastFilledBlock;
} }
RecordIndexFreeSpace(&rel->rd_node, nFreePages, freePages); RecordIndexFreeSpace(&rel->rd_node, totFreePages, nFreePages, freePages);
pfree(freePages); pfree(freePages);
/* return statistics */ /* return statistics */
stats->std.pages_free = nFreePages; stats->std.pages_free = totFreePages;
if (needLock) if (needLock)
LockRelationForExtension(rel, ExclusiveLock); LockRelationForExtension(rel, ExclusiveLock);
stats->std.num_pages = RelationGetNumberOfBlocks(rel); stats->std.num_pages = RelationGetNumberOfBlocks(rel);
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtree.c,v 1.150 2006/08/24 01:18:34 tgl Exp $ * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtree.c,v 1.151 2006/09/21 20:31:22 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -53,8 +53,9 @@ typedef struct ...@@ -53,8 +53,9 @@ typedef struct
void *callback_state; void *callback_state;
BTCycleId cycleid; BTCycleId cycleid;
BlockNumber *freePages; BlockNumber *freePages;
int nFreePages; int nFreePages; /* number of entries in freePages[] */
int maxFreePages; int maxFreePages; /* allocated size of freePages[] */
BlockNumber totFreePages; /* true total # of free pages */
MemoryContext pagedelcontext; MemoryContext pagedelcontext;
} BTVacState; } BTVacState;
...@@ -636,6 +637,7 @@ btvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, ...@@ -636,6 +637,7 @@ btvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
vstate.freePages = NULL; /* temporarily */ vstate.freePages = NULL; /* temporarily */
vstate.nFreePages = 0; vstate.nFreePages = 0;
vstate.maxFreePages = 0; vstate.maxFreePages = 0;
vstate.totFreePages = 0;
/* Create a temporary memory context to run _bt_pagedel in */ /* Create a temporary memory context to run _bt_pagedel in */
vstate.pagedelcontext = AllocSetContextCreate(CurrentMemoryContext, vstate.pagedelcontext = AllocSetContextCreate(CurrentMemoryContext,
...@@ -716,6 +718,7 @@ btvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, ...@@ -716,6 +718,7 @@ btvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
new_pages--; new_pages--;
stats->pages_deleted--; stats->pages_deleted--;
vstate.nFreePages--; vstate.nFreePages--;
vstate.totFreePages = vstate.nFreePages; /* can't be more */
} }
if (new_pages != num_pages) if (new_pages != num_pages)
{ {
...@@ -736,7 +739,8 @@ btvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, ...@@ -736,7 +739,8 @@ btvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
* pages in the index, discarding any old info the map may have. We do not * pages in the index, discarding any old info the map may have. We do not
* need to sort the page numbers; they're in order already. * need to sort the page numbers; they're in order already.
*/ */
RecordIndexFreeSpace(&rel->rd_node, vstate.nFreePages, vstate.freePages); RecordIndexFreeSpace(&rel->rd_node, vstate.totFreePages,
vstate.nFreePages, vstate.freePages);
pfree(vstate.freePages); pfree(vstate.freePages);
...@@ -744,7 +748,7 @@ btvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, ...@@ -744,7 +748,7 @@ btvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
/* update statistics */ /* update statistics */
stats->num_pages = num_pages; stats->num_pages = num_pages;
stats->pages_free = vstate.nFreePages; stats->pages_free = vstate.totFreePages;
} }
/* /*
...@@ -816,6 +820,7 @@ restart: ...@@ -816,6 +820,7 @@ restart:
/* Okay to recycle this page */ /* Okay to recycle this page */
if (vstate->nFreePages < vstate->maxFreePages) if (vstate->nFreePages < vstate->maxFreePages)
vstate->freePages[vstate->nFreePages++] = blkno; vstate->freePages[vstate->nFreePages++] = blkno;
vstate->totFreePages++;
stats->pages_deleted++; stats->pages_deleted++;
} }
else if (P_ISDELETED(opaque)) else if (P_ISDELETED(opaque))
...@@ -954,6 +959,7 @@ restart: ...@@ -954,6 +959,7 @@ restart:
{ {
if (vstate->nFreePages < vstate->maxFreePages) if (vstate->nFreePages < vstate->maxFreePages)
vstate->freePages[vstate->nFreePages++] = blkno; vstate->freePages[vstate->nFreePages++] = blkno;
vstate->totFreePages++;
} }
MemoryContextSwitchTo(oldcontext); MemoryContextSwitchTo(oldcontext);
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.339 2006/09/17 22:16:22 tgl Exp $ * $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.340 2006/09/21 20:31:22 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -3314,7 +3314,7 @@ vac_update_fsm(Relation onerel, VacPageList fraged_pages, ...@@ -3314,7 +3314,7 @@ vac_update_fsm(Relation onerel, VacPageList fraged_pages,
} }
} }
RecordRelationFreeSpace(&onerel->rd_node, outPages, pageSpaces); RecordRelationFreeSpace(&onerel->rd_node, outPages, outPages, pageSpaces);
pfree(pageSpaces); pfree(pageSpaces);
} }
......
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/vacuumlazy.c,v 1.78 2006/09/13 17:47:08 tgl Exp $ * $PostgreSQL: pgsql/src/backend/commands/vacuumlazy.c,v 1.79 2006/09/21 20:31:22 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -90,6 +90,7 @@ typedef struct LVRelStats ...@@ -90,6 +90,7 @@ typedef struct LVRelStats
int num_free_pages; /* current # of entries */ int num_free_pages; /* current # of entries */
int max_free_pages; /* # slots allocated in array */ int max_free_pages; /* # slots allocated in array */
PageFreeSpaceInfo *free_pages; /* array or heap of blkno/avail */ PageFreeSpaceInfo *free_pages; /* array or heap of blkno/avail */
BlockNumber tot_free_pages; /* total pages with >= threshold space */
} LVRelStats; } LVRelStats;
...@@ -523,12 +524,21 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats, ...@@ -523,12 +524,21 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
tups_vacuumed, num_tuples, nblocks), tups_vacuumed, num_tuples, nblocks),
errdetail("%.0f dead row versions cannot be removed yet.\n" errdetail("%.0f dead row versions cannot be removed yet.\n"
"There were %.0f unused item pointers.\n" "There were %.0f unused item pointers.\n"
"%u pages contain useful free space.\n"
"%u pages are entirely empty.\n" "%u pages are entirely empty.\n"
"%s.", "%s.",
nkeep, nkeep,
nunused, nunused,
vacrelstats->tot_free_pages,
empty_pages, empty_pages,
pg_rusage_show(&ru0)))); pg_rusage_show(&ru0))));
if (vacrelstats->tot_free_pages > MaxFSMPages)
ereport(WARNING,
(errmsg("relation \"%s.%s\" contains more than \"max_fsm_pages\" pages with useful free space",
get_namespace_name(RelationGetNamespace(onerel)),
relname),
errhint("Consider compacting this relation or increasing the configuration parameter \"max_fsm_pages\".")));
} }
...@@ -793,6 +803,14 @@ lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats, ...@@ -793,6 +803,14 @@ lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats,
} }
} }
vacrelstats->num_free_pages = j; vacrelstats->num_free_pages = j;
/*
* If tot_free_pages was more than num_free_pages, we can't tell for sure
* what its correct value is now, because we don't know which of the
* forgotten pages are getting truncated. Conservatively set it equal
* to num_free_pages.
*/
vacrelstats->tot_free_pages = j;
/* We destroyed the heap ordering, so mark array unordered */ /* We destroyed the heap ordering, so mark array unordered */
vacrelstats->fs_is_heap = false; vacrelstats->fs_is_heap = false;
...@@ -960,6 +978,7 @@ lazy_space_alloc(LVRelStats *vacrelstats, BlockNumber relblocks) ...@@ -960,6 +978,7 @@ lazy_space_alloc(LVRelStats *vacrelstats, BlockNumber relblocks)
vacrelstats->max_free_pages = maxpages; vacrelstats->max_free_pages = maxpages;
vacrelstats->free_pages = (PageFreeSpaceInfo *) vacrelstats->free_pages = (PageFreeSpaceInfo *)
palloc(maxpages * sizeof(PageFreeSpaceInfo)); palloc(maxpages * sizeof(PageFreeSpaceInfo));
vacrelstats->tot_free_pages = 0;
} }
/* /*
...@@ -1009,6 +1028,9 @@ lazy_record_free_space(LVRelStats *vacrelstats, ...@@ -1009,6 +1028,9 @@ lazy_record_free_space(LVRelStats *vacrelstats,
if (avail < vacrelstats->threshold) if (avail < vacrelstats->threshold)
return; return;
/* Count all pages over threshold, even if not enough space in array */
vacrelstats->tot_free_pages++;
/* Copy pointers to local variables for notational simplicity */ /* Copy pointers to local variables for notational simplicity */
pageSpaces = vacrelstats->free_pages; pageSpaces = vacrelstats->free_pages;
n = vacrelstats->max_free_pages; n = vacrelstats->max_free_pages;
...@@ -1138,7 +1160,8 @@ lazy_update_fsm(Relation onerel, LVRelStats *vacrelstats) ...@@ -1138,7 +1160,8 @@ lazy_update_fsm(Relation onerel, LVRelStats *vacrelstats)
qsort(pageSpaces, nPages, sizeof(PageFreeSpaceInfo), qsort(pageSpaces, nPages, sizeof(PageFreeSpaceInfo),
vac_cmp_page_spaces); vac_cmp_page_spaces);
RecordRelationFreeSpace(&onerel->rd_node, nPages, pageSpaces); RecordRelationFreeSpace(&onerel->rd_node, vacrelstats->tot_free_pages,
nPages, pageSpaces);
} }
/* /*
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/storage/freespace.h,v 1.21 2006/07/13 16:49:20 momjian Exp $ * $PostgreSQL: pgsql/src/include/storage/freespace.h,v 1.22 2006/09/21 20:31:22 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -115,7 +115,7 @@ struct FSMRelation ...@@ -115,7 +115,7 @@ struct FSMRelation
FSMRelation *priorPhysical; /* prior rel in arena-storage order */ FSMRelation *priorPhysical; /* prior rel in arena-storage order */
bool isIndex; /* if true, we store only page numbers */ bool isIndex; /* if true, we store only page numbers */
Size avgRequest; /* moving average of space requests */ Size avgRequest; /* moving average of space requests */
int lastPageCount; /* pages passed to RecordRelationFreeSpace */ BlockNumber interestingPages; /* # of pages with useful free space */
int firstChunk; /* chunk # of my first chunk in arena */ int firstChunk; /* chunk # of my first chunk in arena */
int storedPages; /* # of pages stored in arena */ int storedPages; /* # of pages stored in arena */
int nextPage; /* index (from 0) to start next search at */ int nextPage; /* index (from 0) to start next search at */
...@@ -133,6 +133,7 @@ extern int MaxFSMPages; ...@@ -133,6 +133,7 @@ extern int MaxFSMPages;
*/ */
extern void InitFreeSpaceMap(void); extern void InitFreeSpaceMap(void);
extern Size FreeSpaceShmemSize(void); extern Size FreeSpaceShmemSize(void);
extern FSMHeader *GetFreeSpaceMap(void);
extern BlockNumber GetPageWithFreeSpace(RelFileNode *rel, Size spaceNeeded); extern BlockNumber GetPageWithFreeSpace(RelFileNode *rel, Size spaceNeeded);
extern BlockNumber RecordAndGetPageWithFreeSpace(RelFileNode *rel, extern BlockNumber RecordAndGetPageWithFreeSpace(RelFileNode *rel,
...@@ -141,13 +142,15 @@ extern BlockNumber RecordAndGetPageWithFreeSpace(RelFileNode *rel, ...@@ -141,13 +142,15 @@ extern BlockNumber RecordAndGetPageWithFreeSpace(RelFileNode *rel,
Size spaceNeeded); Size spaceNeeded);
extern Size GetAvgFSMRequestSize(RelFileNode *rel); extern Size GetAvgFSMRequestSize(RelFileNode *rel);
extern void RecordRelationFreeSpace(RelFileNode *rel, extern void RecordRelationFreeSpace(RelFileNode *rel,
int nPages, BlockNumber interestingPages,
PageFreeSpaceInfo *pageSpaces); int nPages,
PageFreeSpaceInfo *pageSpaces);
extern BlockNumber GetFreeIndexPage(RelFileNode *rel); extern BlockNumber GetFreeIndexPage(RelFileNode *rel);
extern void RecordIndexFreeSpace(RelFileNode *rel, extern void RecordIndexFreeSpace(RelFileNode *rel,
int nPages, BlockNumber interestingPages,
BlockNumber *pages); int nPages,
BlockNumber *pages);
extern void FreeSpaceMapTruncateRel(RelFileNode *rel, BlockNumber nblocks); extern void FreeSpaceMapTruncateRel(RelFileNode *rel, BlockNumber nblocks);
extern void FreeSpaceMapForgetRel(RelFileNode *rel); extern void FreeSpaceMapForgetRel(RelFileNode *rel);
...@@ -157,7 +160,6 @@ extern void PrintFreeSpaceMapStatistics(int elevel); ...@@ -157,7 +160,6 @@ extern void PrintFreeSpaceMapStatistics(int elevel);
extern void DumpFreeSpaceMap(int code, Datum arg); extern void DumpFreeSpaceMap(int code, Datum arg);
extern void LoadFreeSpaceMap(void); extern void LoadFreeSpaceMap(void);
extern FSMHeader *GetFreeSpaceMap(void);
#ifdef FREESPACE_DEBUG #ifdef FREESPACE_DEBUG
extern void DumpFreeSpace(void); extern void DumpFreeSpace(void);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment