diff --git a/doc/src/sgml/runtime.sgml b/doc/src/sgml/runtime.sgml index 53add130cb118fc1469d0c28c063fcf181a4859d..d39d2d5d76fa6c721afcef498c93139e7152f002 100644 --- a/doc/src/sgml/runtime.sgml +++ b/doc/src/sgml/runtime.sgml @@ -1,5 +1,5 @@ @@ -1131,6 +1131,42 @@ dynamic_library_path = '/usr/local/lib:/home/my_project/lib:$libdir:$libdir/cont + + MAX_FSM_RELATIONS (integer) + + + Sets the maximum number of relations (tables) for which free space + will be tracked in the shared free-space map. + The default is 100. This option can only be set at server start. + + + + + + MAX_FSM_PAGES (integer) + + + Sets the maximum number of disk pages for which free space + will be tracked in the shared free-space map. + The default is 10000. This option can only be set at server start. + + + + + + MAX_LOCKS_PER_XACT (integer) + + + The shared lock table is sized on the assumption that at most + max_locks_per_xact * max_connections distinct objects will need + to be locked at any one time. The default, 64, has historically + proven sufficient, but you might need to raise this value if you + have clients that touch many different tables in a single transaction. + This option can only be set at server start. + + + + PORT (integer) diff --git a/src/backend/access/hash/hashpage.c b/src/backend/access/hash/hashpage.c index 156db9078a83763d58eb310c9f1b8e7040c97119..d1b3aaa2325430e45710aff8449bc748d6ec35e7 100644 --- a/src/backend/access/hash/hashpage.c +++ b/src/backend/access/hash/hashpage.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/access/hash/hashpage.c,v 1.30 2001/03/07 21:20:26 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/hash/hashpage.c,v 1.31 2001/06/27 23:31:37 tgl Exp $ * * NOTES * Postgres hash pages look like ordinary relation pages. The opaque @@ -70,18 +70,15 @@ _hash_metapinit(Relation rel) int nbuckets; uint32 nelem; /* number elements */ uint32 lg2nelem; /* _hash_log2(nelem) */ - uint32 nblocks; uint16 i; /* can't be sharing this with anyone, now... */ if (USELOCKING) LockRelation(rel, AccessExclusiveLock); - if ((nblocks = RelationGetNumberOfBlocks(rel)) != 0) - { + if (RelationGetNumberOfBlocks(rel) != 0) elog(ERROR, "Cannot initialize non-empty hash table %s", RelationGetRelationName(rel)); - } metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_WRITE); pg = BufferGetPage(metabuf); diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index 6e0974ac32d4da717732877b2169a08e964c7096..b86425f7d118a4074e3702001899aa0597e511b0 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.119 2001/06/22 19:16:20 wieck Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.120 2001/06/27 23:31:38 tgl Exp $ * * * INTERFACE ROUTINES @@ -121,8 +121,8 @@ heapgettup(Relation relation, { ItemId lpp; Page dp; - int page; - int pages; + BlockNumber page; + BlockNumber pages; int lines; OffsetNumber lineoff; int linesleft; @@ -172,7 +172,7 @@ heapgettup(Relation relation, /* * return null immediately if relation is empty */ - if (!(pages = relation->rd_nblocks)) + if ((pages = relation->rd_nblocks) == 0) { if (BufferIsValid(*buffer)) ReleaseBuffer(*buffer); @@ -233,15 +233,8 @@ heapgettup(Relation relation, { page = ItemPointerGetBlockNumber(tid); /* current page */ } - if (page < 0) - { - if (BufferIsValid(*buffer)) - ReleaseBuffer(*buffer); - *buffer = InvalidBuffer; - tuple->t_datamcxt = NULL; - tuple->t_data = NULL; - return; - } + + Assert(page < pages); *buffer = ReleaseAndReadBuffer(*buffer, relation, @@ -283,15 +276,7 @@ heapgettup(Relation relation, OffsetNumberNext(ItemPointerGetOffsetNumber(tid)); } - if (page >= pages) - { - if (BufferIsValid(*buffer)) - ReleaseBuffer(*buffer); - *buffer = InvalidBuffer; - tuple->t_datamcxt = NULL; - tuple->t_data = NULL; - return; - } + Assert(page < pages); *buffer = ReleaseAndReadBuffer(*buffer, relation, @@ -369,12 +354,11 @@ heapgettup(Relation relation, * and it's time to move to the next. */ LockBuffer(*buffer, BUFFER_LOCK_UNLOCK); - page = (dir < 0) ? (page - 1) : (page + 1); /* * return NULL if we've exhausted all the pages */ - if (page < 0 || page >= pages) + if ((dir < 0) ? (page == 0) : (page+1 >= pages)) { if (BufferIsValid(*buffer)) ReleaseBuffer(*buffer); @@ -384,6 +368,10 @@ heapgettup(Relation relation, return; } + page = (dir < 0) ? (page - 1) : (page + 1); + + Assert(page < pages); + *buffer = ReleaseAndReadBuffer(*buffer, relation, page, diff --git a/src/backend/access/heap/hio.c b/src/backend/access/heap/hio.c index 1451dc2ecc5861321dd6cae0df526ea7e9d5ec2d..3a520f2c3156a274b35d5f102804bfe5ddfef15e 100644 --- a/src/backend/access/heap/hio.c +++ b/src/backend/access/heap/hio.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Id: hio.c,v 1.39 2001/05/16 22:35:12 tgl Exp $ + * $Id: hio.c,v 1.40 2001/06/27 23:31:38 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -147,7 +147,7 @@ RelationGetBufferForTuple(Relation relation, Size len, */ relation->rd_nblocks = RelationGetNumberOfBlocks(relation); - if ((BlockNumber) relation->rd_nblocks > oldnblocks) + if (relation->rd_nblocks > oldnblocks) { /* * Someone else has indeed extended the relation recently. diff --git a/src/backend/access/nbtree/nbtpage.c b/src/backend/access/nbtree/nbtpage.c index 460d6c834c179fe652b2c37b9ceed0d86763a11e..67e1407b22b670296456851dd3f69fd138b04a1a 100644 --- a/src/backend/access/nbtree/nbtpage.c +++ b/src/backend/access/nbtree/nbtpage.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtpage.c,v 1.51 2001/03/22 03:59:14 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtpage.c,v 1.52 2001/06/27 23:31:38 tgl Exp $ * * NOTES * Postgres btree pages look like ordinary relation pages. The opaque @@ -55,7 +55,6 @@ _bt_metapinit(Relation rel) { Buffer buf; Page pg; - int nblocks; BTMetaPageData metad; BTPageOpaque op; @@ -63,11 +62,9 @@ _bt_metapinit(Relation rel) if (USELOCKING) LockRelation(rel, AccessExclusiveLock); - if ((nblocks = RelationGetNumberOfBlocks(rel)) != 0) - { + if (RelationGetNumberOfBlocks(rel) != 0) elog(ERROR, "Cannot initialize non-empty btree %s", RelationGetRelationName(rel)); - } buf = ReadBuffer(rel, P_NEW); pg = BufferGetPage(buf); diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index a7f22cd6cfe66f57fbb522807e36bba9ea0a4360..1f2cdf9131de0265ef28c042cab8c4924a3ccad8 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.168 2001/06/18 16:13:21 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.169 2001/06/27 23:31:38 tgl Exp $ * * * INTERFACE ROUTINES @@ -1089,6 +1089,7 @@ RelationTruncateIndexes(Oid heapId) /* Now truncate the actual data and set blocks to zero */ smgrtruncate(DEFAULT_SMGR, currentIndex, 0); currentIndex->rd_nblocks = 0; + currentIndex->rd_targblock = InvalidBlockNumber; /* Initialize the index and rebuild */ InitIndexStrategy(indexInfo->ii_NumIndexAttrs, @@ -1143,9 +1144,9 @@ heap_truncate(char *relname) DropRelationBuffers(rel); /* Now truncate the actual data and set blocks to zero */ - smgrtruncate(DEFAULT_SMGR, rel, 0); rel->rd_nblocks = 0; + rel->rd_targblock = InvalidBlockNumber; /* If this relation has indexes, truncate the indexes too */ RelationTruncateIndexes(rid); diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index 8046e4229678ec937e4fdd82fc78b423f2d7c430..34989055b620ff7eebbcdfb338c8784d5041dd00 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.154 2001/06/12 05:55:49 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.155 2001/06/27 23:31:38 tgl Exp $ * * * INTERFACE ROUTINES @@ -1456,7 +1456,7 @@ UpdateStats(Oid relid, double reltuples) Relation pg_class; HeapTuple tuple; HeapTuple newtup; - long relpages; + BlockNumber relpages; int i; Form_pg_class rd_rel; Relation idescs[Num_pg_class_indices]; @@ -1558,7 +1558,7 @@ UpdateStats(Oid relid, double reltuples) reltuples = 1000; } else - reltuples = relpages * NTUPLES_PER_PAGE(whichRel->rd_rel->relnatts); + reltuples = (double) relpages * NTUPLES_PER_PAGE(whichRel->rd_rel->relnatts); } /* @@ -1566,7 +1566,7 @@ UpdateStats(Oid relid, double reltuples) * place with the new values so that the cache contains the latest * copy. */ - whichRel->rd_rel->relpages = relpages; + whichRel->rd_rel->relpages = (int32) relpages; whichRel->rd_rel->reltuples = reltuples; /* @@ -1581,7 +1581,7 @@ UpdateStats(Oid relid, double reltuples) */ rd_rel = (Form_pg_class) GETSTRUCT(tuple); LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_EXCLUSIVE); - rd_rel->relpages = relpages; + rd_rel->relpages = (int32) relpages; rd_rel->reltuples = reltuples; LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_UNLOCK); WriteNoReleaseBuffer(pg_class_scan->rs_cbuf); @@ -1600,7 +1600,7 @@ UpdateStats(Oid relid, double reltuples) } replace[Anum_pg_class_relpages - 1] = 'r'; - values[Anum_pg_class_relpages - 1] = Int32GetDatum(relpages); + values[Anum_pg_class_relpages - 1] = Int32GetDatum((int32) relpages); replace[Anum_pg_class_reltuples - 1] = 'r'; values[Anum_pg_class_reltuples - 1] = Float4GetDatum((float4) reltuples); newtup = heap_modifytuple(tuple, pg_class, values, nulls, replace); @@ -1962,6 +1962,7 @@ reindex_index(Oid indexId, bool force, bool inplace) /* Now truncate the actual data and set blocks to zero */ smgrtruncate(DEFAULT_SMGR, iRel, 0); iRel->rd_nblocks = 0; + iRel->rd_targblock = InvalidBlockNumber; } /* Initialize the index and rebuild */ diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index c77b2fe8b9061c4488a37044a1303c19202ab561..9c66842feb6ff7e3a0ef97a6adff2c860d7764c0 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.197 2001/06/22 19:16:21 wieck Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.198 2001/06/27 23:31:38 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -107,8 +107,8 @@ typedef VTupleMoveData *VTupleMove; typedef struct VRelStats { Oid relid; - long num_pages; - long num_tuples; + BlockNumber rel_pages; + double rel_tuples; Size min_tlen; Size max_tlen; bool hasindex; @@ -143,8 +143,8 @@ static void vacuum_heap(VRelStats *vacrelstats, Relation onerel, VacPageList vacpagelist); static void vacuum_page(Relation onerel, Buffer buffer, VacPage vacpage); static void vacuum_index(VacPageList vacpagelist, Relation indrel, - long num_tuples, int keep_tuples); -static void scan_index(Relation indrel, long num_tuples); + double num_tuples, int keep_tuples); +static void scan_index(Relation indrel, double num_tuples); static VacPage tid_reaped(ItemPointer itemptr, VacPageList vacpagelist); static void reap_page(VacPageList vacpagelist, VacPage vacpage); static void vpage_insert(VacPageList vacpagelist, VacPage vpnew); @@ -487,8 +487,8 @@ vacuum_rel(Oid relid) */ vacrelstats = (VRelStats *) palloc(sizeof(VRelStats)); vacrelstats->relid = relid; - vacrelstats->num_pages = 0; - vacrelstats->num_tuples = 0; + vacrelstats->rel_pages = 0; + vacrelstats->rel_tuples = 0; vacrelstats->hasindex = false; GetXmaxRecent(&XmaxRecent); @@ -535,13 +535,13 @@ vacuum_rel(Oid relid) { for (i = 0; i < nindices; i++) vacuum_index(&vacuum_pages, Irel[i], - vacrelstats->num_tuples, 0); + vacrelstats->rel_tuples, 0); } else { /* just scan indices to update statistic */ for (i = 0; i < nindices; i++) - scan_index(Irel[i], vacrelstats->num_tuples); + scan_index(Irel[i], vacrelstats->rel_tuples); } } @@ -562,14 +562,13 @@ vacuum_rel(Oid relid) } else { - /* * Flush dirty pages out to disk. We must do this even if we * didn't do anything else, because we want to ensure that all * tuples have correct on-row commit status on disk (see * bufmgr.c's comments for FlushRelationBuffers()). */ - i = FlushRelationBuffers(onerel, vacrelstats->num_pages); + i = FlushRelationBuffers(onerel, vacrelstats->rel_pages); if (i < 0) elog(ERROR, "VACUUM (vacuum_rel): FlushRelationBuffers returned %d", i); @@ -584,8 +583,8 @@ vacuum_rel(Oid relid) heap_close(onerel, NoLock); /* update statistics in pg_class */ - vac_update_relstats(vacrelstats->relid, vacrelstats->num_pages, - vacrelstats->num_tuples, vacrelstats->hasindex); + vac_update_relstats(vacrelstats->relid, vacrelstats->rel_pages, + vacrelstats->rel_tuples, vacrelstats->hasindex); /* * Complete the transaction and free all temporary memory used. @@ -637,7 +636,7 @@ scan_heap(VRelStats *vacrelstats, Relation onerel, char *relname; VacPage vacpage, vp; - long num_tuples; + double num_tuples; uint32 tups_vacuumed, nkeep, nunused, @@ -662,8 +661,9 @@ scan_heap(VRelStats *vacrelstats, Relation onerel, relname = RelationGetRelationName(onerel); elog(MESSAGE_LEVEL, "--Relation %s--", relname); - tups_vacuumed = num_tuples = nkeep = nunused = ncrash = empty_pages = + tups_vacuumed = nkeep = nunused = ncrash = empty_pages = new_pages = changed_pages = empty_end_pages = 0; + num_tuples = 0; free_size = usable_free_size = 0; nblocks = RelationGetNumberOfBlocks(onerel); @@ -922,7 +922,7 @@ scan_heap(VRelStats *vacrelstats, Relation onerel, } else { - num_tuples++; + num_tuples += 1; notup = false; if (tuple.t_len < min_tlen) min_tlen = tuple.t_len; @@ -966,8 +966,8 @@ scan_heap(VRelStats *vacrelstats, Relation onerel, pfree(vacpage); /* save stats in the rel list for use later */ - vacrelstats->num_tuples = num_tuples; - vacrelstats->num_pages = nblocks; + vacrelstats->rel_tuples = num_tuples; + vacrelstats->rel_pages = nblocks; if (num_tuples == 0) min_tlen = max_tlen = 0; vacrelstats->min_tlen = min_tlen; @@ -1014,7 +1014,7 @@ scan_heap(VRelStats *vacrelstats, Relation onerel, } elog(MESSAGE_LEVEL, "Pages %u: Changed %u, reaped %u, Empty %u, New %u; \ -Tup %lu: Vac %u, Keep/VTL %u/%u, Crash %u, UnUsed %u, MinLen %lu, MaxLen %lu; \ +Tup %.0f: Vac %u, Keep/VTL %u/%u, Crash %u, UnUsed %u, MinLen %lu, MaxLen %lu; \ Re-using: Free/Avail. Space %lu/%lu; EndEmpty/Avail. Pages %u/%u. %s", nblocks, changed_pages, vacuum_pages->num_pages, empty_pages, new_pages, num_tuples, tups_vacuumed, @@ -1048,6 +1048,8 @@ repair_frag(VRelStats *vacrelstats, Relation onerel, cur_buffer; int nblocks, blkno; + BlockNumber last_move_dest_block = 0, + last_vacuum_block; Page page, ToPage = NULL; OffsetNumber offnum, @@ -1069,9 +1071,7 @@ repair_frag(VRelStats *vacrelstats, Relation onerel, vacpage, *curpage; int cur_item = 0; - int last_move_dest_block = -1, - last_vacuum_block, - i = 0; + int i; Size tuple_len; int num_moved, num_fraged_pages, @@ -1117,7 +1117,7 @@ repair_frag(VRelStats *vacrelstats, Relation onerel, * NB: this code depends on the vacuum_pages and fraged_pages lists being * in order, and on fraged_pages being a subset of vacuum_pages. */ - nblocks = vacrelstats->num_pages; + nblocks = vacrelstats->rel_pages; for (blkno = nblocks - vacuum_pages->empty_end_pages - 1; blkno > last_move_dest_block; blkno--) @@ -1152,11 +1152,10 @@ repair_frag(VRelStats *vacrelstats, Relation onerel, else { last_vacuum_page = NULL; - last_vacuum_block = -1; + last_vacuum_block = InvalidBlockNumber; } if (num_fraged_pages > 0 && - fraged_pages->pagedesc[num_fraged_pages - 1]->blkno == - (BlockNumber) blkno) + fraged_pages->pagedesc[num_fraged_pages - 1]->blkno == blkno) { /* page is in fraged_pages too; remove it */ --num_fraged_pages; @@ -1577,7 +1576,7 @@ repair_frag(VRelStats *vacrelstats, Relation onerel, } END_CRIT_SECTION(); - if (((int) destvacpage->blkno) > last_move_dest_block) + if (destvacpage->blkno > last_move_dest_block) last_move_dest_block = destvacpage->blkno; /* @@ -1710,9 +1709,9 @@ repair_frag(VRelStats *vacrelstats, Relation onerel, InvalidOffsetNumber, LP_USED); if (newoff == InvalidOffsetNumber) { - elog(STOP, "\ -failed to add item with len = %lu to page %u (free space %lu, nusd %u, noff %u)", - (unsigned long) tuple_len, cur_page->blkno, (unsigned long) cur_page->free, + elog(STOP, "failed to add item with len = %lu to page %u (free space %lu, nusd %u, noff %u)", + (unsigned long) tuple_len, + cur_page->blkno, (unsigned long) cur_page->free, cur_page->offsets_used, cur_page->offsets_free); } newitemid = PageGetItemId(ToPage, newoff); @@ -1746,7 +1745,7 @@ failed to add item with len = %lu to page %u (free space %lu, nusd %u, noff %u)" cur_page->offsets_used++; num_moved++; cur_page->free = ((PageHeader) ToPage)->pd_upper - ((PageHeader) ToPage)->pd_lower; - if (((int) cur_page->blkno) > last_move_dest_block) + if (cur_page->blkno > last_move_dest_block) last_move_dest_block = cur_page->blkno; vacpage->offsets[vacpage->offsets_free++] = offnum; @@ -1882,7 +1881,7 @@ failed to add item with len = %lu to page %u (free space %lu, nusd %u, noff %u)" checked_moved = 0; for (i = 0, curpage = vacuum_pages->pagedesc; i < vacuumed_pages; i++, curpage++) { - Assert((*curpage)->blkno < (BlockNumber) blkno); + Assert((*curpage)->blkno < blkno); buf = ReadBuffer(onerel, (*curpage)->blkno); LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE); page = BufferGetPage(buf); @@ -1959,11 +1958,11 @@ failed to add item with len = %lu to page %u (free space %lu, nusd %u, noff %u)" Assert(keep_tuples >= 0); for (i = 0; i < nindices; i++) vacuum_index(&Nvacpagelist, Irel[i], - vacrelstats->num_tuples, keep_tuples); + vacrelstats->rel_tuples, keep_tuples); } /* clean moved tuples from last page in Nvacpagelist list */ - if (vacpage->blkno == (BlockNumber) (blkno - 1) && + if (vacpage->blkno == (blkno - 1) && vacpage->offsets_free > 0) { OffsetNumber unbuf[BLCKSZ/sizeof(OffsetNumber)]; @@ -2037,8 +2036,7 @@ failed to add item with len = %lu to page %u (free space %lu, nusd %u, noff %u)" if (blkno < nblocks) { blkno = smgrtruncate(DEFAULT_SMGR, onerel, blkno); - Assert(blkno >= 0); - vacrelstats->num_pages = blkno; /* set new number of blocks */ + vacrelstats->rel_pages = blkno; /* set new number of blocks */ } if (Irel != (Relation *) NULL) /* pfree index' allocations */ @@ -2063,7 +2061,8 @@ vacuum_heap(VRelStats *vacrelstats, Relation onerel, VacPageList vacuum_pages) { Buffer buf; VacPage *vacpage; - long nblocks; + BlockNumber relblocks; + int nblocks; int i; nblocks = vacuum_pages->num_pages; @@ -2087,10 +2086,10 @@ vacuum_heap(VRelStats *vacrelstats, Relation onerel, VacPageList vacuum_pages) * tuples have correct on-row commit status on disk (see bufmgr.c's * comments for FlushRelationBuffers()). */ - Assert(vacrelstats->num_pages >= vacuum_pages->empty_end_pages); - nblocks = vacrelstats->num_pages - vacuum_pages->empty_end_pages; + Assert(vacrelstats->rel_pages >= (BlockNumber) vacuum_pages->empty_end_pages); + relblocks = vacrelstats->rel_pages - vacuum_pages->empty_end_pages; - i = FlushRelationBuffers(onerel, nblocks); + i = FlushRelationBuffers(onerel, relblocks); if (i < 0) elog(ERROR, "VACUUM (vacuum_heap): FlushRelationBuffers returned %d", i); @@ -2098,12 +2097,11 @@ vacuum_heap(VRelStats *vacrelstats, Relation onerel, VacPageList vacuum_pages) /* truncate relation if there are some empty end-pages */ if (vacuum_pages->empty_end_pages > 0) { - elog(MESSAGE_LEVEL, "Rel %s: Pages: %lu --> %lu.", + elog(MESSAGE_LEVEL, "Rel %s: Pages: %u --> %u.", RelationGetRelationName(onerel), - vacrelstats->num_pages, nblocks); - nblocks = smgrtruncate(DEFAULT_SMGR, onerel, nblocks); - Assert(nblocks >= 0); - vacrelstats->num_pages = nblocks; /* set new number of + vacrelstats->rel_pages, relblocks); + relblocks = smgrtruncate(DEFAULT_SMGR, onerel, relblocks); + vacrelstats->rel_pages = relblocks; /* set new number of * blocks */ } } @@ -2148,12 +2146,12 @@ vacuum_page(Relation onerel, Buffer buffer, VacPage vacpage) * */ static void -scan_index(Relation indrel, long num_tuples) +scan_index(Relation indrel, double num_tuples) { RetrieveIndexResult res; IndexScanDesc iscan; - long nitups; - int nipages; + BlockNumber nipages; + double nitups; VacRUsage ru0; init_rusage(&ru0); @@ -2165,7 +2163,7 @@ scan_index(Relation indrel, long num_tuples) while ((res = index_getnext(iscan, ForwardScanDirection)) != (RetrieveIndexResult) NULL) { - nitups++; + nitups += 1; pfree(res); } @@ -2175,12 +2173,12 @@ scan_index(Relation indrel, long num_tuples) nipages = RelationGetNumberOfBlocks(indrel); vac_update_relstats(RelationGetRelid(indrel), nipages, nitups, false); - elog(MESSAGE_LEVEL, "Index %s: Pages %u; Tuples %lu. %s", + elog(MESSAGE_LEVEL, "Index %s: Pages %u; Tuples %.0f. %s", RelationGetRelationName(indrel), nipages, nitups, show_rusage(&ru0)); if (nitups != num_tuples) - elog(NOTICE, "Index %s: NUMBER OF INDEX' TUPLES (%lu) IS NOT THE SAME AS HEAP' (%lu).\ + elog(NOTICE, "Index %s: NUMBER OF INDEX' TUPLES (%.0f) IS NOT THE SAME AS HEAP' (%.0f).\ \n\tRecreate the index.", RelationGetRelationName(indrel), nitups, num_tuples); @@ -2200,14 +2198,14 @@ scan_index(Relation indrel, long num_tuples) */ static void vacuum_index(VacPageList vacpagelist, Relation indrel, - long num_tuples, int keep_tuples) + double num_tuples, int keep_tuples) { RetrieveIndexResult res; IndexScanDesc iscan; ItemPointer heapptr; int tups_vacuumed; - long num_index_tuples; - int num_pages; + BlockNumber num_pages; + double num_index_tuples; VacPage vp; VacRUsage ru0; @@ -2242,7 +2240,7 @@ vacuum_index(VacPageList vacpagelist, Relation indrel, index_delete(indrel, &res->index_iptr); } else - num_index_tuples++; + num_index_tuples += 1; pfree(res); } @@ -2254,13 +2252,13 @@ vacuum_index(VacPageList vacpagelist, Relation indrel, vac_update_relstats(RelationGetRelid(indrel), num_pages, num_index_tuples, false); - elog(MESSAGE_LEVEL, "Index %s: Pages %u; Tuples %lu: Deleted %u. %s", + elog(MESSAGE_LEVEL, "Index %s: Pages %u; Tuples %.0f: Deleted %u. %s", RelationGetRelationName(indrel), num_pages, num_index_tuples - keep_tuples, tups_vacuumed, show_rusage(&ru0)); if (num_index_tuples != num_tuples + keep_tuples) - elog(NOTICE, "Index %s: NUMBER OF INDEX' TUPLES (%lu) IS NOT THE SAME AS HEAP' (%lu).\ + elog(NOTICE, "Index %s: NUMBER OF INDEX' TUPLES (%.0f) IS NOT THE SAME AS HEAP' (%.0f).\ \n\tRecreate the index.", RelationGetRelationName(indrel), num_index_tuples, num_tuples); @@ -2333,7 +2331,7 @@ tid_reaped(ItemPointer itemptr, VacPageList vacpagelist) * these are. */ void -vac_update_relstats(Oid relid, long num_pages, double num_tuples, +vac_update_relstats(Oid relid, BlockNumber num_pages, double num_tuples, bool hasindex) { Relation rd; @@ -2361,8 +2359,8 @@ vac_update_relstats(Oid relid, long num_pages, double num_tuples, /* overwrite the existing statistics in the tuple */ pgcform = (Form_pg_class) GETSTRUCT(&rtup); + pgcform->relpages = (int32) num_pages; pgcform->reltuples = num_tuples; - pgcform->relpages = num_pages; pgcform->relhasindex = hasindex; /* invalidate the tuple in the cache and write the buffer */ diff --git a/src/backend/storage/Makefile b/src/backend/storage/Makefile index d9f654491102dbfcb932103b800f4d53c892b277..ace37e6ac66c68ecac4f980c766503d1a6ae648f 100644 --- a/src/backend/storage/Makefile +++ b/src/backend/storage/Makefile @@ -1,14 +1,14 @@ # # Makefile for the storage manager subsystem # -# $Header: /cvsroot/pgsql/src/backend/storage/Makefile,v 1.8 2000/08/31 16:10:30 petere Exp $ +# $Header: /cvsroot/pgsql/src/backend/storage/Makefile,v 1.9 2001/06/27 23:31:39 tgl Exp $ # subdir = src/backend/storage top_builddir = ../../.. include $(top_builddir)/src/Makefile.global -SUBDIRS := buffer file ipc large_object lmgr page smgr +SUBDIRS := buffer file freespace ipc large_object lmgr page smgr SUBDIROBJS := $(SUBDIRS:%=%/SUBSYS.o) all: SUBSYS.o diff --git a/src/backend/storage/freespace/Makefile b/src/backend/storage/freespace/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..9d4c5c5793bf739742281deeaeaec4347c99c006 --- /dev/null +++ b/src/backend/storage/freespace/Makefile @@ -0,0 +1,30 @@ +#------------------------------------------------------------------------- +# +# Makefile-- +# Makefile for storage/freespace +# +# IDENTIFICATION +# $Header: /cvsroot/pgsql/src/backend/storage/freespace/Makefile,v 1.1 2001/06/27 23:31:39 tgl Exp $ +# +#------------------------------------------------------------------------- + +subdir = src/backend/storage/freespace +top_builddir = ../../../.. +include $(top_builddir)/src/Makefile.global + +OBJS = freespace.o + +all: SUBSYS.o + +SUBSYS.o: $(OBJS) + $(LD) $(LDREL) $(LDOUT) SUBSYS.o $(OBJS) + +depend dep: + $(CC) -MM $(CFLAGS) *.c >depend + +clean: + rm -f SUBSYS.o $(OBJS) + +ifeq (depend,$(wildcard depend)) +include depend +endif diff --git a/src/backend/storage/freespace/freespace.c b/src/backend/storage/freespace/freespace.c new file mode 100644 index 0000000000000000000000000000000000000000..84f7066348ef3a7fc8e75ebe0950387457e85f79 --- /dev/null +++ b/src/backend/storage/freespace/freespace.c @@ -0,0 +1,183 @@ +/*------------------------------------------------------------------------- + * + * freespace.c + * POSTGRES free space map for quickly finding free space in relations + * + * + * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/backend/storage/freespace/freespace.c,v 1.1 2001/06/27 23:31:39 tgl Exp $ + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "storage/freespace.h" +#include "storage/itemid.h" +#include "storage/shmem.h" + + +/* + * Shared free-space-map objects + * + * Note: we handle pointers to these items as pointers, not as SHMEM_OFFSETs. + * This assumes that all processes accessing the map will have the shared + * memory segment mapped at the same place in their address space. + */ +typedef struct FSMHeader FSMHeader; +typedef struct FSMRelation FSMRelation; +typedef struct FSMChunk FSMChunk; + +/* Header for whole map */ +struct FSMHeader +{ + HTAB *relationHash; /* hashtable of FSMRelation entries */ + FSMRelation *relationList; /* FSMRelations in order by recency of use */ + int numRelations; /* number of FSMRelations now in use */ + FSMChunk *freeChunks; /* linked list of currently-free chunks */ +}; + +/* + * Per-relation struct --- this is an entry in the shared hash table. + * The hash key is the RelFileNode value (hence, we look at the physical + * relation ID, not the logical ID, which is appropriate). + */ +struct FSMRelation +{ + RelFileNode key; /* hash key (must be first) */ + FSMRelation *nextRel; /* next rel in order by recency of use */ + FSMRelation *priorRel; /* prior rel in order by recency of use */ + FSMChunk *relChunks; /* linked list of page info chunks */ +}; + +#define SHMEM_FSMHASH_KEYSIZE sizeof(RelFileNode) +#define SHMEM_FSMHASH_DATASIZE (sizeof(FSMRelation) - SHMEM_FSMHASH_KEYSIZE) + +#define CHUNKPAGES 32 /* each chunk can store this many pages */ + +struct FSMChunk +{ + FSMChunk *next; /* linked-list link */ + int numPages; /* number of pages described here */ + BlockNumber pages[CHUNKPAGES]; /* page numbers within relation */ + ItemLength bytes[CHUNKPAGES]; /* free space available on each page */ +}; + + +SPINLOCK FreeSpaceLock; /* in Shmem or created in + * CreateSpinlocks() */ + +int MaxFSMRelations; /* these are set by guc.c */ +int MaxFSMPages; + +static FSMHeader *FreeSpaceMap; /* points to FSMHeader in shared memory */ + + +/* + * InitFreeSpaceMap -- Initialize the freespace module. + * + * This must be called once during shared memory initialization. + * It builds the empty free space map table. FreeSpaceLock must also be + * initialized at some point, but is not touched here --- we assume there is + * no need for locking, since only the calling process can be accessing shared + * memory as yet. FreeSpaceShmemSize() was called previously while computing + * the space needed for shared memory. + */ +void +InitFreeSpaceMap(void) +{ + HASHCTL info; + FSMChunk *chunks, + *prevchunk; + int nchunks; + + /* Create table header */ + FreeSpaceMap = (FSMHeader *) ShmemAlloc(sizeof(FSMHeader)); + if (FreeSpaceMap == NULL) + elog(FATAL, "Insufficient shared memory for free space map"); + MemSet(FreeSpaceMap, 0, sizeof(FSMHeader)); + + /* Create hashtable for FSMRelations */ + info.keysize = SHMEM_FSMHASH_KEYSIZE; + info.datasize = SHMEM_FSMHASH_DATASIZE; + info.hash = tag_hash; + + FreeSpaceMap->relationHash = ShmemInitHash("Free Space Map Hash", + MaxFSMRelations / 10, + MaxFSMRelations, + &info, + (HASH_ELEM | HASH_FUNCTION)); + + if (!FreeSpaceMap->relationHash) + elog(FATAL, "Insufficient shared memory for free space map"); + + /* Allocate FSMChunks and fill up the free-chunks list */ + nchunks = (MaxFSMPages - 1) / CHUNKPAGES + 1; + + chunks = (FSMChunk *) ShmemAlloc(nchunks * sizeof(FSMChunk)); + if (chunks == NULL) + elog(FATAL, "Insufficient shared memory for free space map"); + + prevchunk = NULL; + while (nchunks-- > 0) + { + chunks->next = prevchunk; + prevchunk = chunks; + chunks++; + } + FreeSpaceMap->freeChunks = prevchunk; +} + + +int +FreeSpaceShmemSize(void) +{ + int size; + int nchunks; + + /* + * There is no point in allowing less than one "chunk" per relation, + * so force MaxFSMPages to be at least CHUNKPAGES * MaxFSMRelations. + */ + Assert(MaxFSMRelations > 0); + if (MaxFSMPages < CHUNKPAGES * MaxFSMRelations) + MaxFSMPages = CHUNKPAGES * MaxFSMRelations; + + /* table header */ + size = MAXALIGN(sizeof(FSMHeader)); + + /* hash table, including the FSMRelation objects */ + size += hash_estimate_size(MaxFSMRelations, + SHMEM_FSMHASH_KEYSIZE, + SHMEM_FSMHASH_DATASIZE); + + /* FSMChunk objects */ + nchunks = (MaxFSMPages - 1) / CHUNKPAGES + 1; + + size += MAXALIGN(nchunks * sizeof(FSMChunk)); + + return size; +} + + +void +FreeSpaceMapForgetRel(RelFileNode *rel) +{ +} + + +#ifdef FREESPACE_DEBUG +/* + * Dump contents of freespace map for debugging. + * + * We assume caller holds the FreeSpaceLock, or is otherwise unconcerned + * about other processes. + */ +void +DumpFreeSpace(void) +{ +} + +#endif /* FREESPACE_DEBUG */ diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c index ed42e51a925f3e6277e6713a184c1de823e9c0bf..75736c8f240bf03394957fd74b86246783d26351 100644 --- a/src/backend/storage/ipc/ipci.c +++ b/src/backend/storage/ipc/ipci.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipci.c,v 1.40 2001/03/22 03:59:45 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipci.c,v 1.41 2001/06/27 23:31:39 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -19,6 +19,7 @@ #include "miscadmin.h" #include "access/xlog.h" #include "storage/bufmgr.h" +#include "storage/freespace.h" #include "storage/lmgr.h" #include "storage/proc.h" #include "storage/sinval.h" @@ -47,8 +48,12 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int maxBackends) * moderately-accurate estimates for the big hogs, plus 100K for the * stuff that's too small to bother with estimating. */ - size = BufferShmemSize() + LockShmemSize(maxBackends) + - XLOGShmemSize() + SLockShmemSize() + SInvalShmemSize(maxBackends); + size = BufferShmemSize(); + size += LockShmemSize(maxBackends); + size += XLOGShmemSize(); + size += SLockShmemSize(); + size += SInvalShmemSize(maxBackends); + size += FreeSpaceShmemSize(); #ifdef STABLE_MEMORY_STORAGE size += MMShmemSize(); #endif @@ -96,4 +101,9 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int maxBackends) * Set up shared-inval messaging */ CreateSharedInvalidationState(maxBackends); + + /* + * Set up free-space map + */ + InitFreeSpaceMap(); } diff --git a/src/backend/storage/ipc/spin.c b/src/backend/storage/ipc/spin.c index 33308f0cc1f9aa4c83fbf88ab6f431107daecfe1..05bf5acbbb333de94477c74e4354b1240b918ead 100644 --- a/src/backend/storage/ipc/spin.c +++ b/src/backend/storage/ipc/spin.c @@ -14,7 +14,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/storage/ipc/Attic/spin.c,v 1.32 2001/03/22 03:59:45 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/storage/ipc/Attic/spin.c,v 1.33 2001/06/27 23:31:39 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -31,19 +31,18 @@ /* Probably should move these to an appropriate header file */ -extern SPINLOCK ShmemLock; -extern SPINLOCK ShmemIndexLock; extern SPINLOCK BufMgrLock; -extern SPINLOCK LockMgrLock; -extern SPINLOCK ProcStructLock; -extern SPINLOCK SInvalLock; extern SPINLOCK OidGenLockId; extern SPINLOCK XidGenLockId; extern SPINLOCK ControlFileLockId; - +extern SPINLOCK ShmemLock; +extern SPINLOCK ShmemIndexLock; +extern SPINLOCK LockMgrLock; +extern SPINLOCK SInvalLock; +extern SPINLOCK ProcStructLock; +extern SPINLOCK FreeSpaceLock; #ifdef STABLE_MEMORY_STORAGE extern SPINLOCK MMCacheLock; - #endif @@ -57,16 +56,16 @@ extern SPINLOCK MMCacheLock; static void InitSpinLockIDs(void) { - ShmemLock = (SPINLOCK) SHMEMLOCKID; - ShmemIndexLock = (SPINLOCK) SHMEMINDEXLOCKID; BufMgrLock = (SPINLOCK) BUFMGRLOCKID; - LockMgrLock = (SPINLOCK) LOCKMGRLOCKID; - ProcStructLock = (SPINLOCK) PROCSTRUCTLOCKID; - SInvalLock = (SPINLOCK) SINVALLOCKID; OidGenLockId = (SPINLOCK) OIDGENLOCKID; XidGenLockId = (SPINLOCK) XIDGENLOCKID; ControlFileLockId = (SPINLOCK) CNTLFILELOCKID; - + ShmemLock = (SPINLOCK) SHMEMLOCKID; + ShmemIndexLock = (SPINLOCK) SHMEMINDEXLOCKID; + LockMgrLock = (SPINLOCK) LOCKMGRLOCKID; + SInvalLock = (SPINLOCK) SINVALLOCKID; + ProcStructLock = (SPINLOCK) PROCSTRUCTLOCKID; + FreeSpaceLock = (SPINLOCK) FREESPACELOCKID; #ifdef STABLE_MEMORY_STORAGE MMCacheLock = (SPINLOCK) MMCACHELOCKID; #endif diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c index 577b420797ed8fa6cd5d50bdd3072fe8b152086b..3eb010482749117420e9c0b758ec28dfc00a43c9 100644 --- a/src/backend/storage/lmgr/lock.c +++ b/src/backend/storage/lmgr/lock.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.89 2001/06/22 00:04:59 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.90 2001/06/27 23:31:39 tgl Exp $ * * NOTES * Outside modules can create a lock table and acquire/release @@ -40,6 +40,13 @@ #include "utils/memutils.h" #include "utils/ps_status.h" + +/* This configuration variable is used to set the lock table size */ +int max_locks_per_xact; /* set by guc.c */ + +#define NLOCKENTS(maxBackends) (max_locks_per_xact * (maxBackends)) + + static int WaitOnLock(LOCKMETHOD lockmethod, LOCKMODE lockmode, LOCK *lock, HOLDER *holder); static void LockCountMyLocks(SHMEM_OFFSET lockOffset, PROC *proc, @@ -1388,6 +1395,7 @@ int LockShmemSize(int maxBackends) { int size = 0; + long max_table_size = NLOCKENTS(maxBackends); size += MAXALIGN(sizeof(PROC_HDR)); /* ProcGlobal */ size += maxBackends * MAXALIGN(sizeof(PROC)); /* each MyProc */ @@ -1395,12 +1403,12 @@ LockShmemSize(int maxBackends) * lockMethodTable->ctl */ /* lockHash table */ - size += hash_estimate_size(NLOCKENTS(maxBackends), + size += hash_estimate_size(max_table_size, SHMEM_LOCKTAB_KEYSIZE, SHMEM_LOCKTAB_DATASIZE); /* holderHash table */ - size += hash_estimate_size(NLOCKENTS(maxBackends), + size += hash_estimate_size(max_table_size, SHMEM_HOLDERTAB_KEYSIZE, SHMEM_HOLDERTAB_DATASIZE); diff --git a/src/backend/storage/smgr/md.c b/src/backend/storage/smgr/md.c index 762aceda73c28635908111abf9f94daa070d29bb..54054ee137e13ca3dfb9868e2b7e46fd6e7ae26d 100644 --- a/src/backend/storage/smgr/md.c +++ b/src/backend/storage/smgr/md.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/storage/smgr/md.c,v 1.85 2001/06/06 17:07:46 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/storage/smgr/md.c,v 1.86 2001/06/27 23:31:39 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -72,10 +72,10 @@ static MemoryContext MdCxt; /* context for all my allocations */ /* routines declared here */ static void mdclose_fd(int fd); static int _mdfd_getrelnfd(Relation reln); -static MdfdVec *_mdfd_openseg(Relation reln, int segno, int oflags); -static MdfdVec *_mdfd_getseg(Relation reln, int blkno); +static MdfdVec *_mdfd_openseg(Relation reln, BlockNumber segno, int oflags); +static MdfdVec *_mdfd_getseg(Relation reln, BlockNumber blkno); -static int _mdfd_blind_getseg(RelFileNode rnode, int blkno); +static int _mdfd_blind_getseg(RelFileNode rnode, BlockNumber blkno); static int _fdvec_alloc(void); static void _fdvec_free(int); @@ -93,7 +93,7 @@ static BlockNumber _mdnblocks(File file, Size blcksz); * Returns SM_SUCCESS or SM_FAIL with errno set as appropriate. */ int -mdinit() +mdinit(void) { int i; @@ -194,11 +194,11 @@ mdunlink(RelFileNode rnode) if (status == SM_SUCCESS) { char *segpath = (char *) palloc(strlen(path) + 12); - int segno; + BlockNumber segno; for (segno = 1;; segno++) { - sprintf(segpath, "%s.%d", path, segno); + sprintf(segpath, "%s.%u", path, segno); if (unlink(segpath) < 0) { /* ENOENT is expected after the last segment... */ @@ -246,7 +246,7 @@ mdextend(Relation reln, BlockNumber blocknum, char *buffer) v = _mdfd_getseg(reln, blocknum); #ifndef LET_OS_MANAGE_FILESIZE - seekpos = (long) (BLCKSZ * (blocknum % RELSEG_SIZE)); + seekpos = (long) (BLCKSZ * (blocknum % ((BlockNumber) RELSEG_SIZE))); #ifdef DIAGNOSTIC if (seekpos >= BLCKSZ * RELSEG_SIZE) elog(FATAL, "seekpos too big!"); @@ -283,7 +283,7 @@ mdextend(Relation reln, BlockNumber blocknum, char *buffer) #ifndef LET_OS_MANAGE_FILESIZE #ifdef DIAGNOSTIC - if (_mdnblocks(v->mdfd_vfd, BLCKSZ) > RELSEG_SIZE) + if (_mdnblocks(v->mdfd_vfd, BLCKSZ) > ((BlockNumber) RELSEG_SIZE)) elog(FATAL, "segment too big!"); #endif #endif @@ -338,7 +338,7 @@ mdopen(Relation reln) Md_fdvec[vfd].mdfd_chain = (MdfdVec *) NULL; #ifdef DIAGNOSTIC - if (_mdnblocks(fd, BLCKSZ) > RELSEG_SIZE) + if (_mdnblocks(fd, BLCKSZ) > ((BlockNumber) RELSEG_SIZE)) elog(FATAL, "segment too big on relopen!"); #endif #endif @@ -438,7 +438,7 @@ mdread(Relation reln, BlockNumber blocknum, char *buffer) v = _mdfd_getseg(reln, blocknum); #ifndef LET_OS_MANAGE_FILESIZE - seekpos = (long) (BLCKSZ * (blocknum % RELSEG_SIZE)); + seekpos = (long) (BLCKSZ * (blocknum % ((BlockNumber) RELSEG_SIZE))); #ifdef DIAGNOSTIC if (seekpos >= BLCKSZ * RELSEG_SIZE) @@ -482,7 +482,7 @@ mdwrite(Relation reln, BlockNumber blocknum, char *buffer) v = _mdfd_getseg(reln, blocknum); #ifndef LET_OS_MANAGE_FILESIZE - seekpos = (long) (BLCKSZ * (blocknum % RELSEG_SIZE)); + seekpos = (long) (BLCKSZ * (blocknum % ((BlockNumber) RELSEG_SIZE))); #ifdef DIAGNOSTIC if (seekpos >= BLCKSZ * RELSEG_SIZE) elog(FATAL, "seekpos too big!"); @@ -516,7 +516,7 @@ mdflush(Relation reln, BlockNumber blocknum, char *buffer) v = _mdfd_getseg(reln, blocknum); #ifndef LET_OS_MANAGE_FILESIZE - seekpos = (long) (BLCKSZ * (blocknum % RELSEG_SIZE)); + seekpos = (long) (BLCKSZ * (blocknum % ((BlockNumber) RELSEG_SIZE))); #ifdef DIAGNOSTIC if (seekpos >= BLCKSZ * RELSEG_SIZE) elog(FATAL, "seekpos too big!"); @@ -561,7 +561,7 @@ mdblindwrt(RelFileNode rnode, return SM_FAIL; #ifndef LET_OS_MANAGE_FILESIZE - seekpos = (long) (BLCKSZ * (blkno % RELSEG_SIZE)); + seekpos = (long) (BLCKSZ * (blkno % ((BlockNumber) RELSEG_SIZE))); #ifdef DIAGNOSTIC if (seekpos >= BLCKSZ * RELSEG_SIZE) elog(FATAL, "seekpos too big!"); @@ -659,16 +659,14 @@ mdblindmarkdirty(RelFileNode rnode, * * Returns # of blocks, elog's on error. */ -int +BlockNumber mdnblocks(Relation reln) { int fd; MdfdVec *v; - #ifndef LET_OS_MANAGE_FILESIZE - int nblocks; - int segno; - + BlockNumber nblocks; + BlockNumber segno; #endif fd = _mdfd_getrelnfd(reln); @@ -679,10 +677,10 @@ mdnblocks(Relation reln) for (;;) { nblocks = _mdnblocks(v->mdfd_vfd, BLCKSZ); - if (nblocks > RELSEG_SIZE) + if (nblocks > ((BlockNumber) RELSEG_SIZE)) elog(FATAL, "segment too big in mdnblocks!"); - if (nblocks < RELSEG_SIZE) - return (segno * RELSEG_SIZE) + nblocks; + if (nblocks < ((BlockNumber) RELSEG_SIZE)) + return (segno * ((BlockNumber) RELSEG_SIZE)) + nblocks; /* * If segment is exactly RELSEG_SIZE, advance to next one. */ @@ -713,18 +711,16 @@ mdnblocks(Relation reln) /* * mdtruncate() -- Truncate relation to specified number of blocks. * - * Returns # of blocks or -1 on error. + * Returns # of blocks or InvalidBlockNumber on error. */ -int -mdtruncate(Relation reln, int nblocks) +BlockNumber +mdtruncate(Relation reln, BlockNumber nblocks) { - int curnblk; int fd; MdfdVec *v; - + BlockNumber curnblk; #ifndef LET_OS_MANAGE_FILESIZE - int priorblocks; - + BlockNumber priorblocks; #endif /* @@ -732,8 +728,8 @@ mdtruncate(Relation reln, int nblocks) * that truncate/delete loop will get them all! */ curnblk = mdnblocks(reln); - if (nblocks < 0 || nblocks > curnblk) - return -1; /* bogus request */ + if (nblocks > curnblk) + return InvalidBlockNumber; /* bogus request */ if (nblocks == curnblk) return nblocks; /* no work */ @@ -748,7 +744,6 @@ mdtruncate(Relation reln, int nblocks) if (priorblocks > nblocks) { - /* * This segment is no longer wanted at all (and has already * been unlinked from the mdfd_chain). We truncate the file @@ -763,27 +758,25 @@ mdtruncate(Relation reln, int nblocks) * segment */ pfree(ov); } - else if (priorblocks + RELSEG_SIZE > nblocks) + else if (priorblocks + ((BlockNumber) RELSEG_SIZE) > nblocks) { - /* * This is the last segment we want to keep. Truncate the file * to the right length, and clear chain link that points to * any remaining segments (which we shall zap). NOTE: if * nblocks is exactly a multiple K of RELSEG_SIZE, we will * truncate the K+1st segment to 0 length but keep it. This is - * mainly so that the right thing happens if nblocks=0. + * mainly so that the right thing happens if nblocks==0. */ - int lastsegblocks = nblocks - priorblocks; + BlockNumber lastsegblocks = nblocks - priorblocks; if (FileTruncate(v->mdfd_vfd, lastsegblocks * BLCKSZ) < 0) - return -1; + return InvalidBlockNumber; v = v->mdfd_chain; ov->mdfd_chain = (MdfdVec *) NULL; } else { - /* * We still need this segment and 0 or more blocks beyond it, * so nothing to do here. @@ -794,7 +787,7 @@ mdtruncate(Relation reln, int nblocks) } #else if (FileTruncate(v->mdfd_vfd, nblocks * BLCKSZ) < 0) - return -1; + return InvalidBlockNumber; #endif return nblocks; @@ -940,7 +933,7 @@ _fdvec_free(int fdvec) } static MdfdVec * -_mdfd_openseg(Relation reln, int segno, int oflags) +_mdfd_openseg(Relation reln, BlockNumber segno, int oflags) { MdfdVec *v; int fd; @@ -953,7 +946,7 @@ _mdfd_openseg(Relation reln, int segno, int oflags) if (segno > 0) { fullpath = (char *) palloc(strlen(path) + 12); - sprintf(fullpath, "%s.%d", path, segno); + sprintf(fullpath, "%s.%u", path, segno); pfree(path); } else @@ -977,7 +970,7 @@ _mdfd_openseg(Relation reln, int segno, int oflags) v->mdfd_chain = (MdfdVec *) NULL; #ifdef DIAGNOSTIC - if (_mdnblocks(fd, BLCKSZ) > RELSEG_SIZE) + if (_mdnblocks(fd, BLCKSZ) > ((BlockNumber) RELSEG_SIZE)) elog(FATAL, "segment too big on openseg!"); #endif #endif @@ -1007,17 +1000,19 @@ _mdfd_getrelnfd(Relation reln) /* Find the segment of the relation holding the specified block */ static MdfdVec * -_mdfd_getseg(Relation reln, int blkno) +_mdfd_getseg(Relation reln, BlockNumber blkno) { MdfdVec *v; - int segno; int fd; - int i; +#ifndef LET_OS_MANAGE_FILESIZE + BlockNumber segno; + BlockNumber i; +#endif fd = _mdfd_getrelnfd(reln); #ifndef LET_OS_MANAGE_FILESIZE - for (v = &Md_fdvec[fd], segno = blkno / RELSEG_SIZE, i = 1; + for (v = &Md_fdvec[fd], segno = blkno / ((BlockNumber) RELSEG_SIZE), i = 1; segno > 0; i++, segno--) { @@ -1038,7 +1033,7 @@ _mdfd_getseg(Relation reln, int blkno) v->mdfd_chain = _mdfd_openseg(reln, i, (segno == 1) ? O_CREAT : 0); if (v->mdfd_chain == (MdfdVec *) NULL) - elog(ERROR, "cannot open segment %d of relation %s (target block %d): %m", + elog(ERROR, "cannot open segment %u of relation %s (target block %u): %m", i, RelationGetRelationName(reln), blkno); } v = v->mdfd_chain; @@ -1064,26 +1059,24 @@ _mdfd_getseg(Relation reln, int blkno) */ static int -_mdfd_blind_getseg(RelFileNode rnode, int blkno) +_mdfd_blind_getseg(RelFileNode rnode, BlockNumber blkno) { char *path; int fd; - #ifndef LET_OS_MANAGE_FILESIZE - int segno; - + BlockNumber segno; #endif path = relpath(rnode); #ifndef LET_OS_MANAGE_FILESIZE /* append the '.segno', if needed */ - segno = blkno / RELSEG_SIZE; + segno = blkno / ((BlockNumber) RELSEG_SIZE); if (segno > 0) { char *segpath = (char *) palloc(strlen(path) + 12); - sprintf(segpath, "%s.%d", path, segno); + sprintf(segpath, "%s.%u", path, segno); pfree(path); path = segpath; } diff --git a/src/backend/storage/smgr/mm.c b/src/backend/storage/smgr/mm.c index 547fc8d8385ef3f0226456557e9140a42c807e73..791c375de0ab2280f6ac41cec1841e211f854570 100644 --- a/src/backend/storage/smgr/mm.c +++ b/src/backend/storage/smgr/mm.c @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/storage/smgr/Attic/mm.c,v 1.23 2001/05/10 20:38:49 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/storage/smgr/Attic/mm.c,v 1.24 2001/06/27 23:31:39 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -489,15 +489,15 @@ mmblindwrt(char *dbstr, /* * mmnblocks() -- Get the number of blocks stored in a relation. * - * Returns # of blocks or -1 on error. + * Returns # of blocks or InvalidBlockNumber on error. */ -int +BlockNumber mmnblocks(Relation reln) { MMRelTag rtag; MMRelHashEntry *rentry; bool found; - int nblocks; + BlockNumber nblocks; if (reln->rd_rel->relisshared) rtag.mmrt_dbid = (Oid) 0; @@ -520,7 +520,7 @@ mmnblocks(Relation reln) if (found) nblocks = rentry->mmrhe_nblocks; else - nblocks = -1; + nblocks = InvalidBlockNumber; SpinRelease(MMCacheLock); diff --git a/src/backend/storage/smgr/smgr.c b/src/backend/storage/smgr/smgr.c index 25598e3cd5615d1ad72f0fc80eb4344c411170c0..56edbec60f298008b5420bca6722013a60e49719 100644 --- a/src/backend/storage/smgr/smgr.c +++ b/src/backend/storage/smgr/smgr.c @@ -11,13 +11,14 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/storage/smgr/smgr.c,v 1.49 2001/05/10 20:38:49 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/storage/smgr/smgr.c,v 1.50 2001/06/27 23:31:39 tgl Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" #include "storage/bufmgr.h" +#include "storage/freespace.h" #include "storage/smgr.h" #include "utils/memutils.h" @@ -44,8 +45,8 @@ typedef struct f_smgr char *buffer, bool dofsync); int (*smgr_markdirty) (Relation reln, BlockNumber blkno); int (*smgr_blindmarkdirty) (RelFileNode, BlockNumber blkno); - int (*smgr_nblocks) (Relation reln); - int (*smgr_truncate) (Relation reln, int nblocks); + BlockNumber (*smgr_nblocks) (Relation reln); + BlockNumber (*smgr_truncate) (Relation reln, BlockNumber nblocks); int (*smgr_commit) (void); /* may be NULL */ int (*smgr_abort) (void); /* may be NULL */ int (*smgr_sync) (void); @@ -433,16 +434,10 @@ smgrblindmarkdirty(int16 which, * Returns the number of blocks on success, aborts the current * transaction on failure. */ -int +BlockNumber smgrnblocks(int16 which, Relation reln) { - int nblocks; - - if ((nblocks = (*(smgrsw[which].smgr_nblocks)) (reln)) < 0) - elog(ERROR, "cannot count blocks for %s: %m", - RelationGetRelationName(reln)); - - return nblocks; + return (*(smgrsw[which].smgr_nblocks)) (reln); } /* @@ -452,16 +447,24 @@ smgrnblocks(int16 which, Relation reln) * Returns the number of blocks on success, aborts the current * transaction on failure. */ -int -smgrtruncate(int16 which, Relation reln, int nblocks) +BlockNumber +smgrtruncate(int16 which, Relation reln, BlockNumber nblocks) { - int newblks; + BlockNumber newblks; newblks = nblocks; if (smgrsw[which].smgr_truncate) { - if ((newblks = (*(smgrsw[which].smgr_truncate)) (reln, nblocks)) < 0) - elog(ERROR, "cannot truncate %s to %d blocks: %m", + /* + * Tell the free space map to forget this relation, so that it + * stops caching info about the deleted blocks. XXX perhaps + * tell it to forget only info about blocks beyond nblocks? + */ + FreeSpaceMapForgetRel(&reln->rd_node); + + newblks = (*(smgrsw[which].smgr_truncate)) (reln, nblocks); + if (newblks == InvalidBlockNumber) + elog(ERROR, "cannot truncate %s to %u blocks: %m", RelationGetRelationName(reln), nblocks); } @@ -481,7 +484,6 @@ smgrDoPendingDeletes(bool isCommit) pendingDeletes = pending->next; if (pending->atCommit == isCommit) { - /* * Get rid of any leftover buffers for the rel (shouldn't be * any in the commit case, but there can be in the abort @@ -489,6 +491,13 @@ smgrDoPendingDeletes(bool isCommit) */ DropRelFileNodeBuffers(pending->relnode); + /* + * Tell the free space map to forget this relation. It won't + * be accessed any more anyway, but we may as well recycle the + * map space quickly. + */ + FreeSpaceMapForgetRel(&pending->relnode); + /* * And delete the physical files. * diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 7b90122b9f20989122f97d5c9973c1a58ce6cb4b..00b66b2575b2856c78a166e4e95f2333bf4970ec 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.139 2001/06/22 19:16:23 wieck Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.140 2001/06/27 23:31:39 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -25,7 +25,6 @@ * NOTES * The following code contains many undocumented hacks. Please be * careful.... - * */ #include "postgres.h" @@ -63,7 +62,6 @@ /* * hardcoded tuple descriptors. see lib/backend/catalog/pg_attribute.h - * */ static FormData_pg_attribute Desc_pg_class[Natts_pg_class] = {Schema_pg_class}; static FormData_pg_attribute Desc_pg_attribute[Natts_pg_attribute] = {Schema_pg_attribute}; @@ -76,7 +74,6 @@ static FormData_pg_attribute Desc_pg_log[Natts_pg_log] = {Schema_pg_log}; * * Relations are looked up two ways, by name and by id, * thus there are two hash tables for referencing them. - * */ static HTAB *RelationNameCache; static HTAB *RelationIdCache; @@ -105,7 +102,6 @@ static bool criticalRelcachesBuilt = false; /* * RelationBuildDescInfo exists so code can be shared * between RelationIdGetRelation() and RelationNameGetRelation() - * */ typedef struct RelationBuildDescInfo { @@ -139,7 +135,6 @@ typedef struct relnodecacheent /* * macros to manipulate name cache and id cache - * */ #define RelationCacheInsert(RELATION) \ do { \ @@ -285,7 +280,6 @@ static List *insert_ordered_oid(List *list, Oid datum); /* * RelationIdGetRelation() and RelationNameGetRelation() * support functions - * */ @@ -298,7 +292,6 @@ static List *insert_ordered_oid(List *list, Oid datum); * * NB: the returned tuple has been copied into palloc'd storage * and must eventually be freed with heap_freetuple. - * */ static HeapTuple ScanPgRelation(RelationBuildDescInfo buildinfo) @@ -327,7 +320,6 @@ scan_pg_rel_seq(RelationBuildDescInfo buildinfo) /* * form a scan key - * */ switch (buildinfo.infotype) { @@ -352,7 +344,6 @@ scan_pg_rel_seq(RelationBuildDescInfo buildinfo) /* * open pg_class and fetch a tuple - * */ pg_class_desc = heap_openr(RelationRelationName, AccessShareLock); pg_class_scan = heap_beginscan(pg_class_desc, 0, SnapshotNow, 1, &key); @@ -360,7 +351,6 @@ scan_pg_rel_seq(RelationBuildDescInfo buildinfo) /* * get set to return tuple - * */ if (!HeapTupleIsValid(pg_class_tuple)) return_tuple = pg_class_tuple; @@ -372,7 +362,6 @@ scan_pg_rel_seq(RelationBuildDescInfo buildinfo) * returned here without having the corresponding buffer pinned. * so when the buffer gets replaced, all hell breaks loose. this * bug is discovered and killed by wei on 9/27/91. - * */ return_tuple = heap_copytuple(pg_class_tuple); } @@ -435,7 +424,6 @@ scan_pg_rel_ind(RelationBuildDescInfo buildinfo) * If 'relation' is NULL, allocate a new RelationData object. * If not, reuse the given object (that path is taken only when * we have to rebuild a relcache entry during RelationClearRelation). - * */ static Relation AllocateRelationDesc(Relation relation, Form_pg_class relp) @@ -448,16 +436,15 @@ AllocateRelationDesc(Relation relation, Form_pg_class relp) /* * allocate space for new relation descriptor, if needed - * */ if (relation == NULL) relation = (Relation) palloc(sizeof(RelationData)); /* * clear all fields of reldesc - * */ MemSet((char *) relation, 0, sizeof(RelationData)); + relation->rd_targblock = InvalidBlockNumber; /* make sure relation is marked as having no open file yet */ relation->rd_fd = -1; @@ -471,7 +458,6 @@ AllocateRelationDesc(Relation relation, Form_pg_class relp) * wouldn't know if the value is valid ... bottom line is that relacl * *cannot* be retrieved from the relcache. Get it from the syscache * if you need it. - * */ relationForm = (Form_pg_class) palloc(CLASS_TUPLE_SIZE); @@ -493,7 +479,6 @@ AllocateRelationDesc(Relation relation, Form_pg_class relp) * * Form the relation's tuple descriptor from information in * the pg_attribute, pg_attrdef & pg_relcheck system cataloges. - * */ static void RelationBuildTupleDesc(RelationBuildDescInfo buildinfo, @@ -574,7 +559,6 @@ build_tupdesc_seq(RelationBuildDescInfo buildinfo, /* * form a scan key - * */ ScanKeyEntryInitialize(&key, 0, Anum_pg_attribute_attrelid, @@ -583,14 +567,12 @@ build_tupdesc_seq(RelationBuildDescInfo buildinfo, /* * open pg_attribute and begin a scan - * */ pg_attribute_desc = heap_openr(AttributeRelationName, AccessShareLock); pg_attribute_scan = heap_beginscan(pg_attribute_desc, 0, SnapshotNow, 1, &key); /* * add attribute data to relation->rd_att - * */ need = relation->rd_rel->relnatts; @@ -639,7 +621,6 @@ build_tupdesc_seq(RelationBuildDescInfo buildinfo, /* * end the scan and close the attribute relation - * */ heap_endscan(pg_attribute_scan); heap_close(pg_attribute_desc, AccessShareLock); @@ -648,7 +629,6 @@ build_tupdesc_seq(RelationBuildDescInfo buildinfo, * The attcacheoff values we read from pg_attribute should all be -1 * ("unknown"). Verify this if assert checking is on. They will be * computed when and if needed during tuple access. - * */ #ifdef USE_ASSERT_CHECKING { @@ -664,7 +644,6 @@ build_tupdesc_seq(RelationBuildDescInfo buildinfo, * attribute: it must be zero. This eliminates the need for special * cases for attnum=1 that used to exist in fastgetattr() and * index_getattr(). - * */ relation->rd_att->attrs[0]->attcacheoff = 0; @@ -758,7 +737,6 @@ build_tupdesc_ind(RelationBuildDescInfo buildinfo, * The attcacheoff values we read from pg_attribute should all be -1 * ("unknown"). Verify this if assert checking is on. They will be * computed when and if needed during tuple access. - * */ #ifdef USE_ASSERT_CHECKING for (i = 0; i < relation->rd_rel->relnatts; i++) @@ -770,7 +748,6 @@ build_tupdesc_ind(RelationBuildDescInfo buildinfo, * attribute: it must be zero. This eliminates the need for special * cases for attnum=1 that used to exist in fastgetattr() and * index_getattr(). - * */ relation->rd_att->attrs[0]->attcacheoff = 0; @@ -791,7 +768,6 @@ build_tupdesc_ind(RelationBuildDescInfo buildinfo, * entry, because that keeps the update logic in RelationClearRelation() * manageable. The other subsidiary data structures are simple enough * to be easy to free explicitly, anyway. - * */ static void RelationBuildRuleLock(Relation relation) @@ -814,7 +790,7 @@ RelationBuildRuleLock(Relation relation) */ rulescxt = AllocSetContextCreate(CacheMemoryContext, RelationGetRelationName(relation), - 0, /* minsize */ + 0, /* minsize */ 1024, /* initsize */ 1024); /* maxsize */ relation->rd_rulescxt = rulescxt; @@ -822,7 +798,6 @@ RelationBuildRuleLock(Relation relation) /* * form an array to hold the rewrite rules (the array is extended if * necessary) - * */ maxlocks = 4; rules = (RewriteRule **) @@ -831,7 +806,6 @@ RelationBuildRuleLock(Relation relation) /* * form a scan key - * */ ScanKeyEntryInitialize(&key, 0, Anum_pg_rewrite_ev_class, @@ -840,7 +814,6 @@ RelationBuildRuleLock(Relation relation) /* * open pg_rewrite and begin a scan - * */ pg_rewrite_desc = heap_openr(RewriteRelationName, AccessShareLock); pg_rewrite_scan = heap_beginscan(pg_rewrite_desc, 0, SnapshotNow, 1, &key); @@ -908,14 +881,12 @@ RelationBuildRuleLock(Relation relation) /* * end the scan and close the attribute relation - * */ heap_endscan(pg_rewrite_scan); heap_close(pg_rewrite_desc, AccessShareLock); /* * form a RuleLock and insert into relation - * */ rulelock = (RuleLock *) MemoryContextAlloc(rulescxt, sizeof(RuleLock)); rulelock->numLocks = numlocks; @@ -930,7 +901,6 @@ RelationBuildRuleLock(Relation relation) * Determine whether two RuleLocks are equivalent * * Probably this should be in the rules code someplace... - * */ static bool equalRuleLocks(RuleLock *rlock1, RuleLock *rlock2) @@ -994,9 +964,9 @@ equalRuleLocks(RuleLock *rlock1, RuleLock *rlock2) * fields: * * File rd_fd; open file descriptor - * int rd_nblocks; number of blocks in rel + * BlockNumber rd_nblocks; number of blocks in rel * it will be set in ambeginscan() - * uint16 rd_refcnt; reference count + * int rd_refcnt; reference count * Form_pg_am rd_am; AM tuple * Form_pg_class rd_rel; RELATION tuple * Oid rd_id; relation's object id @@ -1022,20 +992,17 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo, /* * find the tuple in pg_class corresponding to the given relation id - * */ pg_class_tuple = ScanPgRelation(buildinfo); /* * if no such tuple exists, return NULL - * */ if (!HeapTupleIsValid(pg_class_tuple)) return NULL; /* * get information from the pg_class_tuple - * */ relid = pg_class_tuple->t_data->t_oid; relp = (Form_pg_class) GETSTRUCT(pg_class_tuple); @@ -1043,37 +1010,31 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo, /* * allocate storage for the relation descriptor, and copy * pg_class_tuple to relation->rd_rel. - * */ relation = AllocateRelationDesc(oldrelation, relp); /* * now we can free the memory allocated for pg_class_tuple - * */ heap_freetuple(pg_class_tuple); /* * initialize the relation's relation id (relation->rd_id) - * */ RelationGetRelid(relation) = relid; /* * initialize relation->rd_refcnt - * */ RelationSetReferenceCount(relation, 1); /* * normal relations are not nailed into the cache - * */ relation->rd_isnailed = false; /* * initialize the access method information (relation->rd_am) - * */ relam = relation->rd_rel->relam; if (OidIsValid(relam)) @@ -1082,13 +1043,11 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo, /* * initialize the tuple descriptor (relation->rd_att). - * */ RelationBuildTupleDesc(buildinfo, relation); /* * Fetch rules and triggers that affect this relation - * */ if (relation->rd_rel->relhasrules) RelationBuildRuleLock(relation); @@ -1105,14 +1064,12 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo, /* * initialize index strategy and support information for this relation - * */ if (OidIsValid(relam)) IndexedAccessMethodInitialize(relation); /* * initialize the relation lock manager information - * */ RelationInitLockInfo(relation); /* see lmgr.c */ @@ -1144,7 +1101,6 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo, /* * insert newly created relation into proper relcaches, restore memory * context and return the new reldesc. - * */ oldcxt = MemoryContextSwitchTo(CacheMemoryContext); RelationCacheInsert(relation); @@ -1214,11 +1170,14 @@ formrdesc(char *relationName, * allocate new relation desc */ relation = (Relation) palloc(sizeof(RelationData)); - MemSet((char *) relation, 0, sizeof(RelationData)); /* - * don't open the unix file yet.. + * clear all fields of reldesc */ + MemSet((char *) relation, 0, sizeof(RelationData)); + relation->rd_targblock = InvalidBlockNumber; + + /* make sure relation is marked as having no open file yet */ relation->rd_fd = -1; /* @@ -1329,7 +1288,6 @@ fixrdesc(char *relationName) /* * find the tuple in pg_class corresponding to the given relation name - * */ buildinfo.infotype = INFO_RELNAME; buildinfo.i.info_name = relationName; @@ -1343,7 +1301,6 @@ fixrdesc(char *relationName) /* * find the pre-made relcache entry (better be there!) - * */ relation = RelationNameCacheGetRelation(relationName); if (!RelationIsValid(relation)) @@ -1353,7 +1310,6 @@ fixrdesc(char *relationName) /* * and copy pg_class_tuple to relation->rd_rel. (See notes in * AllocateRelationDesc()) - * */ Assert(relation->rd_rel != NULL); memcpy((char *) relation->rd_rel, (char *) relp, CLASS_TUPLE_SIZE); @@ -1378,7 +1334,6 @@ fixrdesc(char *relationName) * NB: relation ref count is incremented if successful. * Caller should eventually decrement count. (Usually, * that happens by calling RelationClose().) - * */ Relation RelationIdCacheGetRelation(Oid relationId) @@ -1403,7 +1358,6 @@ RelationIdCacheGetRelation(Oid relationId) * RelationNameCacheGetRelation * * As above, but lookup by name. - * */ static Relation RelationNameCacheGetRelation(const char *relationName) @@ -1457,7 +1411,6 @@ RelationNodeCacheGetRelation(RelFileNode rnode) * NB: relation ref count is incremented, or set to 1 if new entry. * Caller should eventually decrement count. (Usually, * that happens by calling RelationClose().) - * */ Relation RelationIdGetRelation(Oid relationId) @@ -1467,14 +1420,12 @@ RelationIdGetRelation(Oid relationId) /* * increment access statistics - * */ IncrHeapAccessStat(local_RelationIdGetRelation); IncrHeapAccessStat(global_RelationIdGetRelation); /* * first try and get a reldesc from the cache - * */ rd = RelationIdCacheGetRelation(relationId); if (RelationIsValid(rd)) @@ -1483,7 +1434,6 @@ RelationIdGetRelation(Oid relationId) /* * no reldesc in the cache, so have RelationBuildDesc() build one and * add it. - * */ buildinfo.infotype = INFO_RELID; buildinfo.i.info_id = relationId; @@ -1496,7 +1446,6 @@ RelationIdGetRelation(Oid relationId) * RelationNameGetRelation * * As above, but lookup by name. - * */ Relation RelationNameGetRelation(const char *relationName) @@ -1507,7 +1456,6 @@ RelationNameGetRelation(const char *relationName) /* * increment access statistics - * */ IncrHeapAccessStat(local_RelationNameGetRelation); IncrHeapAccessStat(global_RelationNameGetRelation); @@ -1515,7 +1463,6 @@ RelationNameGetRelation(const char *relationName) /* * if caller is looking for a temp relation, substitute its real name; * we only index temp rels by their real names. - * */ temprelname = get_temp_rel_by_username(relationName); if (temprelname != NULL) @@ -1523,7 +1470,6 @@ RelationNameGetRelation(const char *relationName) /* * first try and get a reldesc from the cache - * */ rd = RelationNameCacheGetRelation(relationName); if (RelationIsValid(rd)) @@ -1532,7 +1478,6 @@ RelationNameGetRelation(const char *relationName) /* * no reldesc in the cache, so have RelationBuildDesc() build one and * add it. - * */ buildinfo.infotype = INFO_RELNAME; buildinfo.i.info_name = (char *) relationName; @@ -1556,7 +1501,6 @@ RelationNameGetRelation(const char *relationName) * with aset.c's CLOBBER_FREED_MEMORY option, this provides a good test * to catch references to already-released relcache entries. It slows * things down quite a bit, however. - * */ void RelationClose(Relation relation) @@ -1577,7 +1521,6 @@ RelationClose(Relation relation) * This function is especially for nailed relations. * relhasindex/relfilenode could be changed even for * nailed relations. - * */ static void RelationReloadClassinfo(Relation relation) @@ -1616,7 +1559,6 @@ RelationReloadClassinfo(Relation relation) * usually used when we are notified of a change to an open relation * (one with refcount > 0). However, this routine just does whichever * it's told to do; callers must determine which they want. - * */ static void RelationClearRelation(Relation relation, bool rebuildIt) @@ -1631,7 +1573,10 @@ RelationClearRelation(Relation relation, bool rebuildIt) * a vacuum truncation. */ if (relation->rd_fd >= 0) + { smgrclose(DEFAULT_SMGR, relation); + relation->rd_fd = -1; + } /* * Never, never ever blow away a nailed-in system relation, because @@ -1702,13 +1647,13 @@ RelationClearRelation(Relation relation, bool rebuildIt) * we save/restore rd_nblocks (in case it is a local relation) * *and* call RelationGetNumberOfBlocks (in case it isn't). */ - uint16 old_refcnt = relation->rd_refcnt; + int old_refcnt = relation->rd_refcnt; bool old_myxactonly = relation->rd_myxactonly; TupleDesc old_att = relation->rd_att; RuleLock *old_rules = relation->rd_rules; MemoryContext old_rulescxt = relation->rd_rulescxt; TriggerDesc *old_trigdesc = relation->trigdesc; - int old_nblocks = relation->rd_nblocks; + BlockNumber old_nblocks = relation->rd_nblocks; RelationBuildDescInfo buildinfo; buildinfo.infotype = INFO_RELID; @@ -1767,7 +1712,6 @@ RelationClearRelation(Relation relation, bool rebuildIt) * RelationFlushRelation * * Rebuild the relation if it is open (refcount > 0), else blow it away. - * */ static void RelationFlushRelation(Relation relation) @@ -1801,7 +1745,6 @@ RelationFlushRelation(Relation relation) * RelationClearRelation + if the relation is myxactonly then * remove the relation descriptor from the newly created * relation list. - * */ void RelationForgetRelation(Oid rid) @@ -1851,7 +1794,6 @@ RelationForgetRelation(Oid rid) * safer to process them, so that our *own* SI update messages will * have the same effects during CommandCounterIncrement for both * local and nonlocal relations. - * */ void RelationIdInvalidateRelationCacheByRelationId(Oid relationId) @@ -1989,7 +1931,6 @@ RelationCacheAbortWalker(Relation *relationPtr, Datum dummy) * RelationRegisterRelation - * register the Relation descriptor of a newly created relation * with the relation descriptor Cache. - * */ void RelationRegisterRelation(Relation relation) @@ -2048,7 +1989,6 @@ RelationPurgeLocalRelation(bool xactCommitted) * RelationCacheInitialize * * This initializes the relation descriptor cache. - * */ #define INITRELCACHESIZE 400 @@ -2061,7 +2001,6 @@ RelationCacheInitialize(void) /* * switch to cache memory context - * */ if (!CacheMemoryContext) CreateCacheMemoryContext(); @@ -2070,7 +2009,6 @@ RelationCacheInitialize(void) /* * create global caches - * */ MemSet(&ctl, 0, (int) sizeof(ctl)); ctl.keysize = sizeof(NameData); @@ -2093,7 +2031,6 @@ RelationCacheInitialize(void) * be in the cache. * * NB: see also the list in RelationCacheInitializePhase2(). - * */ formrdesc(RelationRelationName, Natts_pg_class, Desc_pg_class); formrdesc(AttributeRelationName, Natts_pg_attribute, Desc_pg_attribute); @@ -2115,7 +2052,6 @@ RelationCacheInitialize(void) * * This completes initialization of the relcache after catcache * is functional and we are able to actually load data from pg_class. - * */ void RelationCacheInitializePhase2(void) @@ -2658,7 +2594,8 @@ init_irels(void) return; } - /* the file descriptor is not yet opened */ + /* reset transient fields */ + ird->rd_targblock = InvalidBlockNumber; ird->rd_fd = -1; ird->rd_node.tblNode = MyDatabaseId; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 2030c7da370e2b1b033b12d311f3bd5409b4f638..c38d98d391119ed9e9f315499135c8c939784cf7 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -4,7 +4,7 @@ * Support for grand unified configuration scheme, including SET * command, configuration file, and command line options. * - * $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.42 2001/06/23 22:23:49 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.43 2001/06/27 23:31:39 tgl Exp $ * * Copyright 2000 by PostgreSQL Global Development Group * Written by Peter Eisentraut . @@ -31,6 +31,8 @@ #include "optimizer/paths.h" #include "optimizer/planmain.h" #include "parser/parse_expr.h" +#include "storage/freespace.h" +#include "storage/lock.h" #include "storage/proc.h" #include "tcop/tcopprot.h" #include "utils/datetime.h" @@ -270,11 +272,16 @@ static struct config_int */ {"max_connections", PGC_POSTMASTER, &MaxBackends, DEF_MAXBACKENDS, 1, MAXBACKENDS, NULL, NULL}, + {"shared_buffers", PGC_POSTMASTER, &NBuffers, DEF_NBUFFERS, 16, INT_MAX, NULL, NULL}, + {"port", PGC_POSTMASTER, &PostPortNumber, DEF_PGPORT, 1, 65535, NULL, NULL}, + {"unix_socket_permissions", PGC_POSTMASTER, &Unix_socket_permissions, + 0777, 0000, 0777, NULL, NULL}, + {"sort_mem", PGC_USERSET, &SortMem, 512, 4*BLCKSZ/1024, INT_MAX, NULL, NULL}, @@ -290,8 +297,13 @@ static struct config_int {"max_expr_depth", PGC_USERSET, &max_expr_depth, DEFAULT_MAX_EXPR_DEPTH, 10, INT_MAX, NULL, NULL}, - {"unix_socket_permissions", PGC_POSTMASTER, &Unix_socket_permissions, - 0777, 0000, 0777, NULL, NULL}, + {"max_fsm_relations", PGC_POSTMASTER, &MaxFSMRelations, + 100, 10, INT_MAX, NULL, NULL}, + {"max_fsm_pages", PGC_POSTMASTER, &MaxFSMPages, + 10000, 1000, INT_MAX, NULL, NULL}, + + {"max_locks_per_xact", PGC_POSTMASTER, &max_locks_per_xact, + 64, 10, INT_MAX, NULL, NULL}, {"checkpoint_segments", PGC_SIGHUP, &CheckPointSegments, 3, 1, INT_MAX, NULL, NULL}, diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index a77666d9f44fcb3065b31f7485a55851c4735d3a..a3042bee83d0f4a22a7865d870f78fc628317d1d 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -44,11 +44,19 @@ #krb_server_keyfile = '' +# +# Shared Memory Size +# +#shared_buffers = 64 # 2*max_connections, min 16 +#max_fsm_relations = 100 # min 10 +#max_fsm_pages = 10000 # min 1000 +#max_locks_per_xact = 64 # min 10 +#wal_buffers = 8 # min 4 + # # Performance # #sort_mem = 512 -#shared_buffers = 64 # 2*max_connections, min 16 #fsync = true @@ -78,7 +86,7 @@ # GEQO Optimizer Parameters # #geqo_threshold = 11 -#geqo_pool_size = 0 #default based in tables, range 128-1024 +#geqo_pool_size = 0 #default based on #tables in query, range 128-1024 #geqo_effort = 1 #geqo_generations = 0 #geqo_random_seed = -1 # auto-compute seed @@ -87,7 +95,6 @@ # # Write-ahead log (WAL) # -#wal_buffers = 8 # min 4 #wal_files = 0 # range 0-64 #wal_sync_method = fsync # fsync or fdatasync or open_sync or open_datasync # Note: default wal_sync_method varies across platforms diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h index 87bb0007aa067dcbfbe15d31cccfbe00f61df460..0d9f66d04b35a8c171b881e8ed004cf4e8ea7da6 100644 --- a/src/include/commands/vacuum.h +++ b/src/include/commands/vacuum.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: vacuum.h,v 1.35 2001/05/07 00:43:25 tgl Exp $ + * $Id: vacuum.h,v 1.36 2001/06/27 23:31:39 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -15,11 +15,14 @@ #define VACUUM_H #include "nodes/parsenodes.h" +#include "storage/block.h" /* in commands/vacuum.c */ extern void vacuum(VacuumStmt *vacstmt); -extern void vac_update_relstats(Oid relid, long num_pages, double num_tuples, +extern void vac_update_relstats(Oid relid, + BlockNumber num_pages, + double num_tuples, bool hasindex); /* in commands/analyze.c */ extern void analyze_rel(Oid relid, VacuumStmt *vacstmt); diff --git a/src/include/storage/freespace.h b/src/include/storage/freespace.h new file mode 100644 index 0000000000000000000000000000000000000000..083accccab8724246bed6421dee7bfa85cecbcd8 --- /dev/null +++ b/src/include/storage/freespace.h @@ -0,0 +1,53 @@ +/*------------------------------------------------------------------------- + * + * freespace.h + * POSTGRES free space map for quickly finding free space in relations + * + * + * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * $Id: freespace.h,v 1.1 2001/06/27 23:31:39 tgl Exp $ + * + *------------------------------------------------------------------------- + */ +#ifndef FREESPACE_H_ +#define FREESPACE_H_ + +#include "storage/block.h" +#include "storage/relfilenode.h" +#include "storage/spin.h" + + +extern SPINLOCK FreeSpaceLock; + +extern int MaxFSMRelations; +extern int MaxFSMPages; + + +/* + * function prototypes + */ +extern void InitFreeSpaceMap(void); +extern int FreeSpaceShmemSize(void); + +extern BlockNumber GetPageWithFreeSpace(RelFileNode *rel, Size spaceNeeded); +extern void RecordFreeSpace(RelFileNode *rel, BlockNumber page, + Size spaceAvail); +extern BlockNumber RecordAndGetPageWithFreeSpace(RelFileNode *rel, + BlockNumber oldPage, + Size oldSpaceAvail, + Size spaceNeeded); +extern void MultiRecordFreeSpace(RelFileNode *rel, + BlockNumber minPage, + BlockNumber maxPage, + int nPages, + BlockNumber *pages, + Size *spaceAvail); +extern void FreeSpaceMapForgetRel(RelFileNode *rel); + +#ifdef FREESPACE_DEBUG +extern void DumpFreeSpace(void); +#endif + +#endif /* FREESPACE_H */ diff --git a/src/include/storage/ipc.h b/src/include/storage/ipc.h index aa685fc8ff6072e7c70499b4410f219a5359f1f1..8ce1a8459301dc9b270183510d3f6101150ce207 100644 --- a/src/include/storage/ipc.h +++ b/src/include/storage/ipc.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: ipc.h,v 1.49 2001/03/22 04:01:05 momjian Exp $ + * $Id: ipc.h,v 1.50 2001/06/27 23:31:39 tgl Exp $ * * Some files that would normally need to include only sys/ipc.h must * instead include this file because on Ultrix, sys/ipc.h is not designed @@ -74,6 +74,7 @@ typedef enum _LockId_ LOCKMGRLOCKID, SINVALLOCKID, PROCSTRUCTLOCKID, + FREESPACELOCKID, #ifdef STABLE_MEMORY_STORAGE MMCACHELOCKID, diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h index 2428a782a67dfaa07f718def09f9a3f878758649..30a13649e43a48504bde9c16a230db35334ad890 100644 --- a/src/include/storage/lock.h +++ b/src/include/storage/lock.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: lock.h,v 1.49 2001/06/22 00:04:59 tgl Exp $ + * $Id: lock.h,v 1.50 2001/06/27 23:31:39 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -32,6 +32,8 @@ typedef struct proc PROC; extern SPINLOCK LockMgrLock; +extern int max_locks_per_xact; + #ifdef LOCK_DEBUG extern int Trace_lock_oidmin; extern bool Trace_locks; @@ -41,19 +43,6 @@ extern bool Debug_deadlocks; #endif /* LOCK_DEBUG */ -/* ---------------------- - * The following defines are used to estimate how much shared - * memory the lock manager is going to require. - * See LockShmemSize() in lock.c. - * - * NLOCKS_PER_XACT - The number of unique objects locked in a transaction - * (this should be configurable!) - * NLOCKENTS - The maximum number of lock entries in the lock table. - * ---------------------- - */ -#define NLOCKS_PER_XACT 64 -#define NLOCKENTS(maxBackends) (NLOCKS_PER_XACT*(maxBackends)) - typedef int LOCKMASK; typedef int LOCKMODE; diff --git a/src/include/storage/smgr.h b/src/include/storage/smgr.h index b6c5af72dec52971f4d4c1070104d70bfe1d1507..b4193b5fa82206e64d4762992c6f6e777bb322c8 100644 --- a/src/include/storage/smgr.h +++ b/src/include/storage/smgr.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: smgr.h,v 1.29 2001/05/10 20:38:49 tgl Exp $ + * $Id: smgr.h,v 1.30 2001/06/27 23:31:39 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -43,8 +43,9 @@ extern int smgrblindwrt(int16 which, RelFileNode rnode, extern int smgrblindmarkdirty(int16 which, RelFileNode rnode, BlockNumber blkno); extern int smgrmarkdirty(int16 which, Relation reln, BlockNumber blkno); -extern int smgrnblocks(int16 which, Relation reln); -extern int smgrtruncate(int16 which, Relation reln, int nblocks); +extern BlockNumber smgrnblocks(int16 which, Relation reln); +extern BlockNumber smgrtruncate(int16 which, Relation reln, + BlockNumber nblocks); extern int smgrDoPendingDeletes(bool isCommit); extern int smgrcommit(void); extern int smgrabort(void); @@ -71,8 +72,8 @@ extern int mdmarkdirty(Relation reln, BlockNumber blkno); extern int mdblindwrt(RelFileNode rnode, BlockNumber blkno, char *buffer, bool dofsync); extern int mdblindmarkdirty(RelFileNode rnode, BlockNumber blkno); -extern int mdnblocks(Relation reln); -extern int mdtruncate(Relation reln, int nblocks); +extern BlockNumber mdnblocks(Relation reln); +extern BlockNumber mdtruncate(Relation reln, BlockNumber nblocks); extern int mdcommit(void); extern int mdabort(void); extern int mdsync(void); @@ -95,8 +96,8 @@ extern int mmblindwrt(char *dbname, char *relname, Oid dbid, Oid relid, extern int mmmarkdirty(Relation reln, BlockNumber blkno); extern int mmblindmarkdirty(char *dbname, char *relname, Oid dbid, Oid relid, BlockNumber blkno); -extern int mmnblocks(Relation reln); -extern int mmtruncate(Relation reln, int nblocks); +extern BlockNumber mmnblocks(Relation reln); +extern BlockNumber mmtruncate(Relation reln, BlockNumber nblocks); extern int mmcommit(void); extern int mmabort(void); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index c2a9d0982f7c1626fa6b7c362b6acc841a614f35..ef74317fda500ce5e769dbe2e45df58abb20253e 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: rel.h,v 1.50 2001/06/22 19:16:24 wieck Exp $ + * $Id: rel.h,v 1.51 2001/06/27 23:31:40 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -19,8 +19,9 @@ #include "catalog/pg_am.h" #include "catalog/pg_class.h" #include "rewrite/prs2lock.h" -#include "storage/relfilenode.h" +#include "storage/block.h" #include "storage/fd.h" +#include "storage/relfilenode.h" /* added to prevent circular dependency. bjm 1999/11/15 */ extern char *get_temp_rel_by_physicalname(const char *relname); @@ -105,9 +106,11 @@ typedef struct PgStat_Info typedef struct RelationData { File rd_fd; /* open file descriptor, or -1 if none */ - RelFileNode rd_node; /* relation file node */ - int rd_nblocks; /* number of blocks in rel */ - uint16 rd_refcnt; /* reference count */ + RelFileNode rd_node; /* file node (physical identifier) */ + BlockNumber rd_nblocks; /* number of blocks in rel */ + BlockNumber rd_targblock; /* current insertion target block, + * or InvalidBlockNumber */ + int rd_refcnt; /* reference count */ bool rd_myxactonly; /* rel uses the local buffer mgr */ bool rd_isnailed; /* rel is nailed in cache */ bool rd_indexfound; /* true if rd_indexlist is valid */