Prevent creating a boatload of empty segments when md.c is asked to

access a ridiculously large block number within a relation.
This commit is contained in:
Tom Lane 2000-07-10 04:32:00 +00:00
parent b54faa1b15
commit f3e5d8620c
1 changed files with 25 additions and 7 deletions

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/smgr/md.c,v 1.72 2000/06/28 03:32:14 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/storage/smgr/md.c,v 1.73 2000/07/10 04:32:00 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -714,9 +714,16 @@ mdnblocks(Relation reln)
if (v->mdfd_chain == (MdfdVec *) NULL) if (v->mdfd_chain == (MdfdVec *) NULL)
{ {
/*
* Because we pass O_CREAT, we will create the next segment
* (with zero length) immediately, if the last segment is of
* length REL_SEGSIZE. This is unnecessary but harmless, and
* testing for the case would take more cycles than it seems
* worth.
*/
v->mdfd_chain = _mdfd_openseg(reln, segno, O_CREAT); v->mdfd_chain = _mdfd_openseg(reln, segno, O_CREAT);
if (v->mdfd_chain == (MdfdVec *) NULL) if (v->mdfd_chain == (MdfdVec *) NULL)
elog(ERROR, "cannot count blocks for %s -- open failed", elog(ERROR, "cannot count blocks for %s -- open failed: %m",
RelationGetRelationName(reln)); RelationGetRelationName(reln));
} }
@ -1038,11 +1045,20 @@ _mdfd_getseg(Relation reln, int blkno)
if (v->mdfd_chain == (MdfdVec *) NULL) if (v->mdfd_chain == (MdfdVec *) NULL)
{ {
v->mdfd_chain = _mdfd_openseg(reln, i, O_CREAT); /*
* We will create the next segment only if the target block
* is within it. This prevents Sorcerer's Apprentice syndrome
* if a bug at higher levels causes us to be handed a ridiculously
* large blkno --- otherwise we could create many thousands of
* empty segment files before reaching the "target" block. We
* should never need to create more than one new segment per call,
* so this restriction seems reasonable.
*/
v->mdfd_chain = _mdfd_openseg(reln, i, (segno == 1) ? O_CREAT : 0);
if (v->mdfd_chain == (MdfdVec *) NULL) if (v->mdfd_chain == (MdfdVec *) NULL)
elog(ERROR, "cannot open segment %d of relation %s", elog(ERROR, "cannot open segment %d of relation %s (target block %d): %m",
i, RelationGetRelationName(reln)); i, RelationGetRelationName(reln), blkno);
} }
v = v->mdfd_chain; v = v->mdfd_chain;
} }
@ -1060,8 +1076,10 @@ _mdfd_getseg(Relation reln, int blkno)
* "blind" with no Relation struct. We assume that we are not likely to * "blind" with no Relation struct. We assume that we are not likely to
* touch the same relation again soon, so we do not create an FD entry for * touch the same relation again soon, so we do not create an FD entry for
* the relation --- we just open a kernel file descriptor which will be * the relation --- we just open a kernel file descriptor which will be
* used and promptly closed. The return value is the kernel descriptor, * used and promptly closed. We also assume that the target block already
* or -1 on failure. * exists, ie, we need not extend the relation.
*
* The return value is the kernel descriptor, or -1 on failure.
*/ */
static int static int