Skip to content

Commit 403bdc4

Browse files
committed
Back-patch fix for 'Sorcerer's Apprentice' syndrome wherein md.c would
create a vast quantity of zero-length files if asked to access a block number far beyond the actual end of a relation.
1 parent aa09aaa commit 403bdc4

File tree

1 file changed

+42
-14
lines changed
  • src/backend/storage/smgr

1 file changed

+42
-14
lines changed

src/backend/storage/smgr/md.c

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/storage/smgr/md.c,v 1.68 2000/05/25 23:30:20 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/storage/smgr/md.c,v 1.68.2.1 2000/09/23 22:11:41 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -130,6 +130,7 @@ mdcreate(Relation reln)
130130
char *path;
131131

132132
Assert(reln->rd_unlinked && reln->rd_fd < 0);
133+
133134
path = relpath(RelationGetPhysicalRelationName(reln));
134135
#ifndef __CYGWIN32__
135136
fd = FileNameOpenFile(path, O_RDWR | O_CREAT | O_EXCL, 0600);
@@ -138,19 +139,21 @@ mdcreate(Relation reln)
138139
#endif
139140

140141
/*
141-
* During bootstrap processing, we skip that check, because pg_time,
142-
* pg_variable, and pg_log get created before their .bki file entries
143-
* are processed.
144-
*
145-
* For cataloged relations,pg_class is guaranteed to have an unique
142+
* For cataloged relations, pg_class is guaranteed to have a unique
146143
* record with the same relname by the unique index. So we are able to
147-
* reuse existent files for new catloged relations. Currently we reuse
144+
* reuse existent files for new cataloged relations. Currently we reuse
148145
* them in the following cases. 1. they are empty. 2. they are used
149146
* for Index relations and their size == BLCKSZ * 2.
147+
*
148+
* During bootstrap processing, we skip that check, because pg_time,
149+
* pg_variable, and pg_log get created before their .bki file entries
150+
* are processed.
150151
*/
151152

152153
if (fd < 0)
153154
{
155+
int save_errno = errno;
156+
154157
if (!IsBootstrapProcessingMode() &&
155158
reln->rd_rel->relkind == RELKIND_UNCATALOGED)
156159
return -1;
@@ -161,11 +164,15 @@ mdcreate(Relation reln)
161164
fd = FileNameOpenFile(path, O_RDWR | O_BINARY, 0600);
162165
#endif
163166
if (fd < 0)
167+
{
168+
/* be sure to return the error reported by create, not open */
169+
errno = save_errno;
164170
return -1;
171+
}
165172
if (!IsBootstrapProcessingMode())
166173
{
167174
bool reuse = false;
168-
int len = FileSeek(fd, 0L, SEEK_END);
175+
long len = FileSeek(fd, 0L, SEEK_END);
169176

170177
if (len == 0)
171178
reuse = true;
@@ -175,9 +182,12 @@ mdcreate(Relation reln)
175182
if (!reuse)
176183
{
177184
FileClose(fd);
185+
/* be sure to return the error reported by create */
186+
errno = save_errno;
178187
return -1;
179188
}
180189
}
190+
errno = 0;
181191
}
182192
reln->rd_unlinked = false;
183193

@@ -733,9 +743,16 @@ mdnblocks(Relation reln)
733743

734744
if (v->mdfd_chain == (MdfdVec *) NULL)
735745
{
746+
/*
747+
* Because we pass O_CREAT, we will create the next segment
748+
* (with zero length) immediately, if the last segment is of
749+
* length REL_SEGSIZE. This is unnecessary but harmless, and
750+
* testing for the case would take more cycles than it seems
751+
* worth.
752+
*/
736753
v->mdfd_chain = _mdfd_openseg(reln, segno, O_CREAT);
737754
if (v->mdfd_chain == (MdfdVec *) NULL)
738-
elog(ERROR, "cannot count blocks for %s -- open failed",
755+
elog(ERROR, "cannot count blocks for %s -- open failed: %m",
739756
RelationGetRelationName(reln));
740757
}
741758

@@ -1075,11 +1092,20 @@ _mdfd_getseg(Relation reln, int blkno)
10751092

10761093
if (v->mdfd_chain == (MdfdVec *) NULL)
10771094
{
1078-
v->mdfd_chain = _mdfd_openseg(reln, i, O_CREAT);
1095+
/*
1096+
* We will create the next segment only if the target block
1097+
* is within it. This prevents Sorcerer's Apprentice syndrome
1098+
* if a bug at higher levels causes us to be handed a ridiculously
1099+
* large blkno --- otherwise we could create many thousands of
1100+
* empty segment files before reaching the "target" block. We
1101+
* should never need to create more than one new segment per call,
1102+
* so this restriction seems reasonable.
1103+
*/
1104+
v->mdfd_chain = _mdfd_openseg(reln, i, (segno == 1) ? O_CREAT : 0);
10791105

10801106
if (v->mdfd_chain == (MdfdVec *) NULL)
1081-
elog(ERROR, "cannot open segment %d of relation %s",
1082-
i, RelationGetRelationName(reln));
1107+
elog(ERROR, "cannot open segment %d of relation %s (target block %d): %m",
1108+
i, RelationGetRelationName(reln), blkno);
10831109
}
10841110
v = v->mdfd_chain;
10851111
}
@@ -1097,8 +1123,10 @@ _mdfd_getseg(Relation reln, int blkno)
10971123
* "blind" with no Relation struct. We assume that we are not likely to
10981124
* touch the same relation again soon, so we do not create an FD entry for
10991125
* the relation --- we just open a kernel file descriptor which will be
1100-
* used and promptly closed. The return value is the kernel descriptor,
1101-
* or -1 on failure.
1126+
* used and promptly closed. We also assume that the target block already
1127+
* exists, ie, we need not extend the relation.
1128+
*
1129+
* The return value is the kernel descriptor, or -1 on failure.
11021130
*/
11031131

11041132
static int

0 commit comments

Comments
 (0)