]> granicus.if.org Git - postgresql/commitdiff
Prevent creating a boatload of empty segments when md.c is asked to
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 10 Jul 2000 04:32:00 +0000 (04:32 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 10 Jul 2000 04:32:00 +0000 (04:32 +0000)
access a ridiculously large block number within a relation.

src/backend/storage/smgr/md.c

index de51e703f8b61f63213433b7bd3c79b7de953572..5baf6935d0a0d8e85ffc1897b0d660cd2fece8ea 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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)
                        {
+                               /*
+                                * 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);
                                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));
                        }
 
@@ -1038,11 +1045,20 @@ _mdfd_getseg(Relation reln, int blkno)
 
                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)
-                               elog(ERROR, "cannot open segment %d of relation %s",
-                                        i, RelationGetRelationName(reln));
+                               elog(ERROR, "cannot open segment %d of relation %s (target block %d): %m",
+                                        i, RelationGetRelationName(reln), blkno);
                }
                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
  * 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
- * used and promptly closed.  The return value is the kernel descriptor,
- * or -1 on failure.
+ * used and promptly closed.  We also assume that the target block already
+ * exists, ie, we need not extend the relation.
+ *
+ * The return value is the kernel descriptor, or -1 on failure.
  */
 
 static int