Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commita9ec978

Browse files
committed
Remove fixed limit on the number of concurrent AllocateFile() requests.
AllocateFile(), AllocateDir(), and some sister routines share a small arrayfor remembering requests, so that the files can be closed on transactionfailure. Previously that array had a fixed size, MAX_ALLOCATED_DESCS (32).While historically that had seemed sufficient, Steve Toutant pointed outthat this meant you couldn't scan more than 32 file_fdw foreign tables inone query, because file_fdw depends on the COPY code which usesAllocateFile(). There are probably other cases, or will be in the future,where this nonconfigurable limit impedes users.We can't completely remove any such limit, at least not without a lot ofwork, since each such request requires a kernel file descriptor and mostplatforms limit the number we can have. (In principle we could"virtualize" these descriptors, as fd.c already does for the main VFD pool,but not without an additional layer of overhead and a lot of notationalimpact on the calling code.) But we can at least let the array size beconfigurable. Hence, change the code to allow up to max_safe_fds/2allocated file requests. On modern platforms this should allow severalhundred concurrent file_fdw scans, or more if one increases the value ofmax_files_per_process. To go much further than that, we'd need to do somemore work on the data structure, since the current code for closingrequests has potentially O(N^2) runtime; but it should still be all rightfor request counts in this range.Back-patch to 9.1 where contrib/file_fdw was introduced.
1 parenta56c92f commita9ec978

File tree

1 file changed

+106
-38
lines changed
  • src/backend/storage/file

1 file changed

+106
-38
lines changed

‎src/backend/storage/file/fd.c

Lines changed: 106 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -179,13 +179,7 @@ static uint64 temporary_files_size = 0;
179179
/*
180180
* List of stdio FILEs and <dirent.h> DIRs opened with AllocateFile
181181
* and AllocateDir.
182-
*
183-
* Since we don't want to encourage heavy use of AllocateFile or AllocateDir,
184-
* it seems OK to put a pretty small maximum limit on the number of
185-
* simultaneously allocated descs.
186182
*/
187-
#defineMAX_ALLOCATED_DESCS 32
188-
189183
typedefenum
190184
{
191185
AllocateDescFile,
@@ -195,16 +189,17 @@ typedef enum
195189
typedefstruct
196190
{
197191
AllocateDescKindkind;
192+
SubTransactionIdcreate_subid;
198193
union
199194
{
200195
FILE*file;
201196
DIR*dir;
202197
}desc;
203-
SubTransactionIdcreate_subid;
204198
}AllocateDesc;
205199

206200
staticintnumAllocatedDescs=0;
207-
staticAllocateDescallocatedDescs[MAX_ALLOCATED_DESCS];
201+
staticintmaxAllocatedDescs=0;
202+
staticAllocateDesc*allocatedDescs=NULL;
208203

209204
/*
210205
* Number of temporary files opened during the current session;
@@ -230,6 +225,7 @@ static intnextTempTableSpace = 0;
230225
* Insert - put a file at the front of the Lru ring
231226
* LruInsert - put a file at the front of the Lru ring and open it
232227
* ReleaseLruFile - Release an fd by closing the last entry in the Lru ring
228+
* ReleaseLruFiles - Release fd(s) until we're under the max_safe_fds limit
233229
* AllocateVfd - grab a free (or new) file record (from VfdArray)
234230
* FreeVfd - free a file record
235231
*
@@ -257,11 +253,14 @@ static void LruDelete(File file);
257253
staticvoidInsert(Filefile);
258254
staticintLruInsert(Filefile);
259255
staticboolReleaseLruFile(void);
256+
staticvoidReleaseLruFiles(void);
260257
staticFileAllocateVfd(void);
261258
staticvoidFreeVfd(Filefile);
262259

263260
staticintFileAccess(Filefile);
264261
staticFileOpenTemporaryFileInTablespace(OidtblspcOid,boolrejectError);
262+
staticboolreserveAllocatedDesc(void);
263+
staticintFreeDesc(AllocateDesc*desc);
265264
staticvoidAtProcExit_Files(intcode,Datumarg);
266265
staticvoidCleanupTempFiles(boolisProcExit);
267266
staticvoidRemovePgTempFilesInDir(constchar*tmpdirname);
@@ -664,11 +663,8 @@ LruInsert(File file)
664663

665664
if (FileIsNotOpen(file))
666665
{
667-
while (nfile+numAllocatedDescs >=max_safe_fds)
668-
{
669-
if (!ReleaseLruFile())
670-
break;
671-
}
666+
/* Close excess kernel FDs. */
667+
ReleaseLruFiles();
672668

673669
/*
674670
* The open could still fail for lack of file descriptors, eg due to
@@ -707,6 +703,9 @@ LruInsert(File file)
707703
return0;
708704
}
709705

706+
/*
707+
* Release one kernel FD by closing the least-recently-used VFD.
708+
*/
710709
staticbool
711710
ReleaseLruFile(void)
712711
{
@@ -725,6 +724,20 @@ ReleaseLruFile(void)
725724
return false;/* no files available to free */
726725
}
727726

727+
/*
728+
* Release kernel FDs as needed to get under the max_safe_fds limit.
729+
* After calling this, it's OK to try to open another file.
730+
*/
731+
staticvoid
732+
ReleaseLruFiles(void)
733+
{
734+
while (nfile+numAllocatedDescs >=max_safe_fds)
735+
{
736+
if (!ReleaseLruFile())
737+
break;
738+
}
739+
}
740+
728741
staticFile
729742
AllocateVfd(void)
730743
{
@@ -878,11 +891,8 @@ PathNameOpenFile(FileName fileName, int fileFlags, int fileMode)
878891
file=AllocateVfd();
879892
vfdP=&VfdCache[file];
880893

881-
while (nfile+numAllocatedDescs >=max_safe_fds)
882-
{
883-
if (!ReleaseLruFile())
884-
break;
885-
}
894+
/* Close excess kernel FDs. */
895+
ReleaseLruFiles();
886896

887897
vfdP->fd=BasicOpenFile(fileName,fileFlags,fileMode);
888898

@@ -1461,6 +1471,66 @@ FilePathName(File file)
14611471
}
14621472

14631473

1474+
/*
1475+
* Make room for another allocatedDescs[] array entry if needed and possible.
1476+
* Returns true if an array element is available.
1477+
*/
1478+
staticbool
1479+
reserveAllocatedDesc(void)
1480+
{
1481+
AllocateDesc*newDescs;
1482+
intnewMax;
1483+
1484+
/* Quick out if array already has a free slot. */
1485+
if (numAllocatedDescs<maxAllocatedDescs)
1486+
return true;
1487+
1488+
/*
1489+
* If the array hasn't yet been created in the current process, initialize
1490+
* it with FD_MINFREE / 2 elements. In many scenarios this is as many as
1491+
* we will ever need, anyway. We don't want to look at max_safe_fds
1492+
* immediately because set_max_safe_fds() may not have run yet.
1493+
*/
1494+
if (allocatedDescs==NULL)
1495+
{
1496+
newMax=FD_MINFREE /2;
1497+
newDescs= (AllocateDesc*)malloc(newMax*sizeof(AllocateDesc));
1498+
/* Out of memory already? Treat as fatal error. */
1499+
if (newDescs==NULL)
1500+
ereport(ERROR,
1501+
(errcode(ERRCODE_OUT_OF_MEMORY),
1502+
errmsg("out of memory")));
1503+
allocatedDescs=newDescs;
1504+
maxAllocatedDescs=newMax;
1505+
return true;
1506+
}
1507+
1508+
/*
1509+
* Consider enlarging the array beyond the initial allocation used above.
1510+
* By the time this happens, max_safe_fds should be known accurately.
1511+
*
1512+
* We mustn't let allocated descriptors hog all the available FDs, and in
1513+
* practice we'd better leave a reasonable number of FDs for VFD use. So
1514+
* set the maximum to max_safe_fds / 2. (This should certainly be at
1515+
* least as large as the initial size, FD_MINFREE / 2.)
1516+
*/
1517+
newMax=max_safe_fds /2;
1518+
if (newMax>maxAllocatedDescs)
1519+
{
1520+
newDescs= (AllocateDesc*)realloc(allocatedDescs,
1521+
newMax*sizeof(AllocateDesc));
1522+
/* Treat out-of-memory as a non-fatal error. */
1523+
if (newDescs==NULL)
1524+
return false;
1525+
allocatedDescs=newDescs;
1526+
maxAllocatedDescs=newMax;
1527+
return true;
1528+
}
1529+
1530+
/* Can't enlarge allocatedDescs[] any more. */
1531+
return false;
1532+
}
1533+
14641534
/*
14651535
* Routines that want to use stdio (ie, FILE*) should use AllocateFile
14661536
* rather than plain fopen(). This lets fd.c deal with freeing FDs if
@@ -1486,16 +1556,15 @@ AllocateFile(const char *name, const char *mode)
14861556
DO_DB(elog(LOG,"AllocateFile: Allocated %d (%s)",
14871557
numAllocatedDescs,name));
14881558

1489-
/*
1490-
* The test against MAX_ALLOCATED_DESCS prevents us from overflowing
1491-
* allocatedFiles[]; the test against max_safe_fds prevents AllocateFile
1492-
* from hogging every one of the available FDs, which'd lead to infinite
1493-
* looping.
1494-
*/
1495-
if (numAllocatedDescs >=MAX_ALLOCATED_DESCS||
1496-
numAllocatedDescs >=max_safe_fds-1)
1497-
elog(ERROR,"exceeded MAX_ALLOCATED_DESCS while trying to open file \"%s\"",
1498-
name);
1559+
/* Can we allocate another non-virtual FD? */
1560+
if (!reserveAllocatedDesc())
1561+
ereport(ERROR,
1562+
(errcode(ERRCODE_INSUFFICIENT_RESOURCES),
1563+
errmsg("exceeded maxAllocatedDescs (%d) while trying to open file \"%s\"",
1564+
maxAllocatedDescs,name)));
1565+
1566+
/* Close excess kernel FDs. */
1567+
ReleaseLruFiles();
14991568

15001569
TryAgain:
15011570
if ((file=fopen(name,mode))!=NULL)
@@ -1602,16 +1671,15 @@ AllocateDir(const char *dirname)
16021671
DO_DB(elog(LOG,"AllocateDir: Allocated %d (%s)",
16031672
numAllocatedDescs,dirname));
16041673

1605-
/*
1606-
* The test against MAX_ALLOCATED_DESCS prevents us from overflowing
1607-
* allocatedDescs[]; the test against max_safe_fds prevents AllocateDir
1608-
* from hogging every one of the available FDs, which'd lead to infinite
1609-
* looping.
1610-
*/
1611-
if (numAllocatedDescs >=MAX_ALLOCATED_DESCS||
1612-
numAllocatedDescs >=max_safe_fds-1)
1613-
elog(ERROR,"exceeded MAX_ALLOCATED_DESCS while trying to open directory \"%s\"",
1614-
dirname);
1674+
/* Can we allocate another non-virtual FD? */
1675+
if (!reserveAllocatedDesc())
1676+
ereport(ERROR,
1677+
(errcode(ERRCODE_INSUFFICIENT_RESOURCES),
1678+
errmsg("exceeded maxAllocatedDescs (%d) while trying to open directory \"%s\"",
1679+
maxAllocatedDescs,dirname)));
1680+
1681+
/* Close excess kernel FDs. */
1682+
ReleaseLruFiles();
16151683

16161684
TryAgain:
16171685
if ((dir=opendir(dirname))!=NULL)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp