<!--
-$Header: /cvsroot/pgsql/doc/src/sgml/runtime.sgml,v 1.69 2001/06/23 00:03:10 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/runtime.sgml,v 1.70 2001/06/27 23:31:37 tgl Exp $
-->
<Chapter Id="runtime">
</listitem>
</varlistentry>
+ <varlistentry>
+ <term>MAX_FSM_RELATIONS (<type>integer</type>)</term>
+ <listitem>
+ <para>
+ 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.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>MAX_FSM_PAGES (<type>integer</type>)</term>
+ <listitem>
+ <para>
+ 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.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>MAX_LOCKS_PER_XACT (<type>integer</type>)</term>
+ <listitem>
+ <para>
+ 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.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term>PORT (<type>integer</type>)</term>
<listitem>
*
*
* 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
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);
*
*
* 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
{
ItemId lpp;
Page dp;
- int page;
- int pages;
+ BlockNumber page;
+ BlockNumber pages;
int lines;
OffsetNumber lineoff;
int linesleft;
/*
* return null immediately if relation is empty
*/
- if (!(pages = relation->rd_nblocks))
+ if ((pages = relation->rd_nblocks) == 0)
{
if (BufferIsValid(*buffer))
ReleaseBuffer(*buffer);
{
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,
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,
* 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);
return;
}
+ page = (dir < 0) ? (page - 1) : (page + 1);
+
+ Assert(page < pages);
+
*buffer = ReleaseAndReadBuffer(*buffer,
relation,
page,
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
*/
relation->rd_nblocks = RelationGetNumberOfBlocks(relation);
- if ((BlockNumber) relation->rd_nblocks > oldnblocks)
+ if (relation->rd_nblocks > oldnblocks)
{
/*
* Someone else has indeed extended the relation recently.
*
*
* 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
{
Buffer buf;
Page pg;
- int nblocks;
BTMetaPageData metad;
BTPageOpaque op;
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);
*
*
* 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
/* 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,
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);
*
*
* 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
Relation pg_class;
HeapTuple tuple;
HeapTuple newtup;
- long relpages;
+ BlockNumber relpages;
int i;
Form_pg_class rd_rel;
Relation idescs[Num_pg_class_indices];
reltuples = 1000;
}
else
- reltuples = relpages * NTUPLES_PER_PAGE(whichRel->rd_rel->relnatts);
+ reltuples = (double) relpages * NTUPLES_PER_PAGE(whichRel->rd_rel->relnatts);
}
/*
* 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;
/*
*/
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);
}
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);
/* 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 */
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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;
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);
*/
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);
{
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);
}
}
}
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);
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.
char *relname;
VacPage vacpage,
vp;
- long num_tuples;
+ double num_tuples;
uint32 tups_vacuumed,
nkeep,
nunused,
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);
}
else
{
- num_tuples++;
+ num_tuples += 1;
notup = false;
if (tuple.t_len < min_tlen)
min_tlen = tuple.t_len;
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;
}
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,
cur_buffer;
int nblocks,
blkno;
+ BlockNumber last_move_dest_block = 0,
+ last_vacuum_block;
Page page,
ToPage = NULL;
OffsetNumber offnum,
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,
* 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--)
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;
}
END_CRIT_SECTION();
- if (((int) destvacpage->blkno) > last_move_dest_block)
+ if (destvacpage->blkno > last_move_dest_block)
last_move_dest_block = destvacpage->blkno;
/*
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);
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;
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);
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)];
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 */
{
Buffer buf;
VacPage *vacpage;
- long nblocks;
+ BlockNumber relblocks;
+ int nblocks;
int i;
nblocks = vacuum_pages->num_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);
/* 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 */
}
}
*
*/
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);
while ((res = index_getnext(iscan, ForwardScanDirection))
!= (RetrieveIndexResult) NULL)
{
- nitups++;
+ nitups += 1;
pfree(res);
}
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);
*/
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;
index_delete(indrel, &res->index_iptr);
}
else
- num_index_tuples++;
+ num_index_tuples += 1;
pfree(res);
}
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);
* 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;
/* 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 */
#
# 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
--- /dev/null
+#-------------------------------------------------------------------------
+#
+# 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
--- /dev/null
+/*-------------------------------------------------------------------------
+ *
+ * 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 */
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
#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"
* 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
* Set up shared-inval messaging
*/
CreateSharedInvalidationState(maxBackends);
+
+ /*
+ * Set up free-space map
+ */
+ InitFreeSpaceMap();
}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
/* 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
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
*
*
* 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
#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,
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 */
* 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);
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
/* 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);
* Returns SM_SUCCESS or SM_FAIL with errno set as appropriate.
*/
int
-mdinit()
+mdinit(void)
{
int i;
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... */
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!");
#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
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
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)
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!");
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!");
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!");
*
* 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);
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.
*/
/*
* 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
/*
* 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 */
if (priorblocks > nblocks)
{
-
/*
* This segment is no longer wanted at all (and has already
* been unlinked from the mdfd_chain). We truncate the file
* 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.
}
#else
if (FileTruncate(v->mdfd_vfd, nblocks * BLCKSZ) < 0)
- return -1;
+ return InvalidBlockNumber;
#endif
return nblocks;
}
static MdfdVec *
-_mdfd_openseg(Relation reln, int segno, int oflags)
+_mdfd_openseg(Relation reln, BlockNumber segno, int oflags)
{
MdfdVec *v;
int fd;
if (segno > 0)
{
fullpath = (char *) palloc(strlen(path) + 12);
- sprintf(fullpath, "%s.%d", path, segno);
+ sprintf(fullpath, "%s.%u", path, segno);
pfree(path);
}
else
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
/* 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--)
{
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;
*/
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;
}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
/*
* 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;
if (found)
nblocks = rentry->mmrhe_nblocks;
else
- nblocks = -1;
+ nblocks = InvalidBlockNumber;
SpinRelease(MMCacheLock);
*
*
* 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"
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);
* 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);
}
/*
* 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);
}
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
*/
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.
*
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
* NOTES
* The following code contains many undocumented hacks. Please be
* careful....
- *
*/
#include "postgres.h"
/*
* 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};
*
* 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;
/*
* RelationBuildDescInfo exists so code can be shared
* between RelationIdGetRelation() and RelationNameGetRelation()
- *
*/
typedef struct RelationBuildDescInfo
{
/*
* macros to manipulate name cache and id cache
- *
*/
#define RelationCacheInsert(RELATION) \
do { \
/*
* RelationIdGetRelation() and RelationNameGetRelation()
* support functions
- *
*/
*
* NB: the returned tuple has been copied into palloc'd storage
* and must eventually be freed with heap_freetuple.
- *
*/
static HeapTuple
ScanPgRelation(RelationBuildDescInfo buildinfo)
/*
* form a scan key
- *
*/
switch (buildinfo.infotype)
{
/*
* 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);
/*
* get set to return tuple
- *
*/
if (!HeapTupleIsValid(pg_class_tuple))
return_tuple = pg_class_tuple;
* 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);
}
* 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)
/*
* 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;
* 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);
*
* Form the relation's tuple descriptor from information in
* the pg_attribute, pg_attrdef & pg_relcheck system cataloges.
- *
*/
static void
RelationBuildTupleDesc(RelationBuildDescInfo buildinfo,
/*
* form a scan key
- *
*/
ScanKeyEntryInitialize(&key, 0,
Anum_pg_attribute_attrelid,
/*
* 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;
/*
* end the scan and close the attribute relation
- *
*/
heap_endscan(pg_attribute_scan);
heap_close(pg_attribute_desc, AccessShareLock);
* 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
{
* 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;
* 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++)
* 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;
* 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)
*/
rulescxt = AllocSetContextCreate(CacheMemoryContext,
RelationGetRelationName(relation),
- 0, /* minsize */
+ 0, /* minsize */
1024, /* initsize */
1024); /* maxsize */
relation->rd_rulescxt = rulescxt;
/*
* form an array to hold the rewrite rules (the array is extended if
* necessary)
- *
*/
maxlocks = 4;
rules = (RewriteRule **)
/*
* form a scan key
- *
*/
ScanKeyEntryInitialize(&key, 0,
Anum_pg_rewrite_ev_class,
/*
* 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);
/*
* 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;
* Determine whether two RuleLocks are equivalent
*
* Probably this should be in the rules code someplace...
- *
*/
static bool
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
/*
* 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);
/*
* 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))
/*
* 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);
/*
* 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 */
/*
* insert newly created relation into proper relcaches, restore memory
* context and return the new reldesc.
- *
*/
oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
RelationCacheInsert(relation);
* 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;
/*
/*
* find the tuple in pg_class corresponding to the given relation name
- *
*/
buildinfo.infotype = INFO_RELNAME;
buildinfo.i.info_name = relationName;
/*
* find the pre-made relcache entry (better be there!)
- *
*/
relation = RelationNameCacheGetRelation(relationName);
if (!RelationIsValid(relation))
/*
* 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);
* NB: relation ref count is incremented if successful.
* Caller should eventually decrement count. (Usually,
* that happens by calling RelationClose().)
- *
*/
Relation
RelationIdCacheGetRelation(Oid relationId)
* RelationNameCacheGetRelation
*
* As above, but lookup by name.
- *
*/
static Relation
RelationNameCacheGetRelation(const char *relationName)
* 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)
/*
* increment access statistics
- *
*/
IncrHeapAccessStat(local_RelationIdGetRelation);
IncrHeapAccessStat(global_RelationIdGetRelation);
/*
* first try and get a reldesc from the cache
- *
*/
rd = RelationIdCacheGetRelation(relationId);
if (RelationIsValid(rd))
/*
* no reldesc in the cache, so have RelationBuildDesc() build one and
* add it.
- *
*/
buildinfo.infotype = INFO_RELID;
buildinfo.i.info_id = relationId;
* RelationNameGetRelation
*
* As above, but lookup by name.
- *
*/
Relation
RelationNameGetRelation(const char *relationName)
/*
* increment access statistics
- *
*/
IncrHeapAccessStat(local_RelationNameGetRelation);
IncrHeapAccessStat(global_RelationNameGetRelation);
/*
* 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)
/*
* first try and get a reldesc from the cache
- *
*/
rd = RelationNameCacheGetRelation(relationName);
if (RelationIsValid(rd))
/*
* no reldesc in the cache, so have RelationBuildDesc() build one and
* add it.
- *
*/
buildinfo.infotype = INFO_RELNAME;
buildinfo.i.info_name = (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)
* This function is especially for nailed relations.
* relhasindex/relfilenode could be changed even for
* nailed relations.
- *
*/
static void
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)
* 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
* 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;
* RelationFlushRelation
*
* Rebuild the relation if it is open (refcount > 0), else blow it away.
- *
*/
static void
RelationFlushRelation(Relation relation)
* RelationClearRelation + if the relation is myxactonly then
* remove the relation descriptor from the newly created
* relation list.
- *
*/
void
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)
* RelationRegisterRelation -
* register the Relation descriptor of a newly created relation
* with the relation descriptor Cache.
- *
*/
void
RelationRegisterRelation(Relation relation)
* RelationCacheInitialize
*
* This initializes the relation descriptor cache.
- *
*/
#define INITRELCACHESIZE 400
/*
* switch to cache memory context
- *
*/
if (!CacheMemoryContext)
CreateCacheMemoryContext();
/*
* create global caches
- *
*/
MemSet(&ctl, 0, (int) sizeof(ctl));
ctl.keysize = sizeof(NameData);
* 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);
*
* This completes initialization of the relcache after catcache
* is functional and we are able to actually load data from pg_class.
- *
*/
void
RelationCacheInitializePhase2(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;
* 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
#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"
*/
{"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},
{"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},
#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
# 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
#
# 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
* 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 $
*
*-------------------------------------------------------------------------
*/
#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);
--- /dev/null
+/*-------------------------------------------------------------------------
+ *
+ * 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 */
* 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
LOCKMGRLOCKID,
SINVALLOCKID,
PROCSTRUCTLOCKID,
+ FREESPACELOCKID,
#ifdef STABLE_MEMORY_STORAGE
MMCACHELOCKID,
* 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 $
*
*-------------------------------------------------------------------------
*/
extern SPINLOCK LockMgrLock;
+extern int max_locks_per_xact;
+
#ifdef LOCK_DEBUG
extern int Trace_lock_oidmin;
extern bool Trace_locks;
#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;
* 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 $
*
*-------------------------------------------------------------------------
*/
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);
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);
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);
* 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 $
*
*-------------------------------------------------------------------------
*/
#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);
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 */