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

Commit8c3fdbb

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 parentd7cb64a commit8c3fdbb

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
@@ -169,13 +169,7 @@ static intnfile = 0;
169169
/*
170170
* List of stdio FILEs and <dirent.h> DIRs opened with AllocateFile
171171
* and AllocateDir.
172-
*
173-
* Since we don't want to encourage heavy use of AllocateFile or AllocateDir,
174-
* it seems OK to put a pretty small maximum limit on the number of
175-
* simultaneously allocated descs.
176172
*/
177-
#defineMAX_ALLOCATED_DESCS 32
178-
179173
typedefenum
180174
{
181175
AllocateDescFile,
@@ -185,16 +179,17 @@ typedef enum
185179
typedefstruct
186180
{
187181
AllocateDescKindkind;
182+
SubTransactionIdcreate_subid;
188183
union
189184
{
190185
FILE*file;
191186
DIR*dir;
192187
}desc;
193-
SubTransactionIdcreate_subid;
194188
}AllocateDesc;
195189

196190
staticintnumAllocatedDescs=0;
197-
staticAllocateDescallocatedDescs[MAX_ALLOCATED_DESCS];
191+
staticintmaxAllocatedDescs=0;
192+
staticAllocateDesc*allocatedDescs=NULL;
198193

199194
/*
200195
* Number of temporary files opened during the current session;
@@ -220,6 +215,7 @@ static intnextTempTableSpace = 0;
220215
* Insert - put a file at the front of the Lru ring
221216
* LruInsert - put a file at the front of the Lru ring and open it
222217
* ReleaseLruFile - Release an fd by closing the last entry in the Lru ring
218+
* ReleaseLruFiles - Release fd(s) until we're under the max_safe_fds limit
223219
* AllocateVfd - grab a free (or new) file record (from VfdArray)
224220
* FreeVfd - free a file record
225221
*
@@ -247,11 +243,14 @@ static void LruDelete(File file);
247243
staticvoidInsert(Filefile);
248244
staticintLruInsert(Filefile);
249245
staticboolReleaseLruFile(void);
246+
staticvoidReleaseLruFiles(void);
250247
staticFileAllocateVfd(void);
251248
staticvoidFreeVfd(Filefile);
252249

253250
staticintFileAccess(Filefile);
254251
staticFileOpenTemporaryFileInTablespace(OidtblspcOid,boolrejectError);
252+
staticboolreserveAllocatedDesc(void);
253+
staticintFreeDesc(AllocateDesc*desc);
255254
staticvoidAtProcExit_Files(intcode,Datumarg);
256255
staticvoidCleanupTempFiles(boolisProcExit);
257256
staticvoidRemovePgTempFilesInDir(constchar*tmpdirname);
@@ -654,11 +653,8 @@ LruInsert(File file)
654653

655654
if (FileIsNotOpen(file))
656655
{
657-
while (nfile+numAllocatedDescs >=max_safe_fds)
658-
{
659-
if (!ReleaseLruFile())
660-
break;
661-
}
656+
/* Close excess kernel FDs. */
657+
ReleaseLruFiles();
662658

663659
/*
664660
* The open could still fail for lack of file descriptors, eg due to
@@ -697,6 +693,9 @@ LruInsert(File file)
697693
return0;
698694
}
699695

696+
/*
697+
* Release one kernel FD by closing the least-recently-used VFD.
698+
*/
700699
staticbool
701700
ReleaseLruFile(void)
702701
{
@@ -715,6 +714,20 @@ ReleaseLruFile(void)
715714
return false;/* no files available to free */
716715
}
717716

717+
/*
718+
* Release kernel FDs as needed to get under the max_safe_fds limit.
719+
* After calling this, it's OK to try to open another file.
720+
*/
721+
staticvoid
722+
ReleaseLruFiles(void)
723+
{
724+
while (nfile+numAllocatedDescs >=max_safe_fds)
725+
{
726+
if (!ReleaseLruFile())
727+
break;
728+
}
729+
}
730+
718731
staticFile
719732
AllocateVfd(void)
720733
{
@@ -868,11 +881,8 @@ PathNameOpenFile(FileName fileName, int fileFlags, int fileMode)
868881
file=AllocateVfd();
869882
vfdP=&VfdCache[file];
870883

871-
while (nfile+numAllocatedDescs >=max_safe_fds)
872-
{
873-
if (!ReleaseLruFile())
874-
break;
875-
}
884+
/* Close excess kernel FDs. */
885+
ReleaseLruFiles();
876886

877887
vfdP->fd=BasicOpenFile(fileName,fileFlags,fileMode);
878888

@@ -1402,6 +1412,66 @@ FilePathName(File file)
14021412
}
14031413

14041414

1415+
/*
1416+
* Make room for another allocatedDescs[] array entry if needed and possible.
1417+
* Returns true if an array element is available.
1418+
*/
1419+
staticbool
1420+
reserveAllocatedDesc(void)
1421+
{
1422+
AllocateDesc*newDescs;
1423+
intnewMax;
1424+
1425+
/* Quick out if array already has a free slot. */
1426+
if (numAllocatedDescs<maxAllocatedDescs)
1427+
return true;
1428+
1429+
/*
1430+
* If the array hasn't yet been created in the current process, initialize
1431+
* it with FD_MINFREE / 2 elements. In many scenarios this is as many as
1432+
* we will ever need, anyway. We don't want to look at max_safe_fds
1433+
* immediately because set_max_safe_fds() may not have run yet.
1434+
*/
1435+
if (allocatedDescs==NULL)
1436+
{
1437+
newMax=FD_MINFREE /2;
1438+
newDescs= (AllocateDesc*)malloc(newMax*sizeof(AllocateDesc));
1439+
/* Out of memory already? Treat as fatal error. */
1440+
if (newDescs==NULL)
1441+
ereport(ERROR,
1442+
(errcode(ERRCODE_OUT_OF_MEMORY),
1443+
errmsg("out of memory")));
1444+
allocatedDescs=newDescs;
1445+
maxAllocatedDescs=newMax;
1446+
return true;
1447+
}
1448+
1449+
/*
1450+
* Consider enlarging the array beyond the initial allocation used above.
1451+
* By the time this happens, max_safe_fds should be known accurately.
1452+
*
1453+
* We mustn't let allocated descriptors hog all the available FDs, and in
1454+
* practice we'd better leave a reasonable number of FDs for VFD use. So
1455+
* set the maximum to max_safe_fds / 2. (This should certainly be at
1456+
* least as large as the initial size, FD_MINFREE / 2.)
1457+
*/
1458+
newMax=max_safe_fds /2;
1459+
if (newMax>maxAllocatedDescs)
1460+
{
1461+
newDescs= (AllocateDesc*)realloc(allocatedDescs,
1462+
newMax*sizeof(AllocateDesc));
1463+
/* Treat out-of-memory as a non-fatal error. */
1464+
if (newDescs==NULL)
1465+
return false;
1466+
allocatedDescs=newDescs;
1467+
maxAllocatedDescs=newMax;
1468+
return true;
1469+
}
1470+
1471+
/* Can't enlarge allocatedDescs[] any more. */
1472+
return false;
1473+
}
1474+
14051475
/*
14061476
* Routines that want to use stdio (ie, FILE*) should use AllocateFile
14071477
* rather than plain fopen(). This lets fd.c deal with freeing FDs if
@@ -1427,16 +1497,15 @@ AllocateFile(const char *name, const char *mode)
14271497
DO_DB(elog(LOG,"AllocateFile: Allocated %d (%s)",
14281498
numAllocatedDescs,name));
14291499

1430-
/*
1431-
* The test against MAX_ALLOCATED_DESCS prevents us from overflowing
1432-
* allocatedFiles[]; the test against max_safe_fds prevents AllocateFile
1433-
* from hogging every one of the available FDs, which'd lead to infinite
1434-
* looping.
1435-
*/
1436-
if (numAllocatedDescs >=MAX_ALLOCATED_DESCS||
1437-
numAllocatedDescs >=max_safe_fds-1)
1438-
elog(ERROR,"exceeded MAX_ALLOCATED_DESCS while trying to open file \"%s\"",
1439-
name);
1500+
/* Can we allocate another non-virtual FD? */
1501+
if (!reserveAllocatedDesc())
1502+
ereport(ERROR,
1503+
(errcode(ERRCODE_INSUFFICIENT_RESOURCES),
1504+
errmsg("exceeded maxAllocatedDescs (%d) while trying to open file \"%s\"",
1505+
maxAllocatedDescs,name)));
1506+
1507+
/* Close excess kernel FDs. */
1508+
ReleaseLruFiles();
14401509

14411510
TryAgain:
14421511
if ((file=fopen(name,mode))!=NULL)
@@ -1543,16 +1612,15 @@ AllocateDir(const char *dirname)
15431612
DO_DB(elog(LOG,"AllocateDir: Allocated %d (%s)",
15441613
numAllocatedDescs,dirname));
15451614

1546-
/*
1547-
* The test against MAX_ALLOCATED_DESCS prevents us from overflowing
1548-
* allocatedDescs[]; the test against max_safe_fds prevents AllocateDir
1549-
* from hogging every one of the available FDs, which'd lead to infinite
1550-
* looping.
1551-
*/
1552-
if (numAllocatedDescs >=MAX_ALLOCATED_DESCS||
1553-
numAllocatedDescs >=max_safe_fds-1)
1554-
elog(ERROR,"exceeded MAX_ALLOCATED_DESCS while trying to open directory \"%s\"",
1555-
dirname);
1615+
/* Can we allocate another non-virtual FD? */
1616+
if (!reserveAllocatedDesc())
1617+
ereport(ERROR,
1618+
(errcode(ERRCODE_INSUFFICIENT_RESOURCES),
1619+
errmsg("exceeded maxAllocatedDescs (%d) while trying to open directory \"%s\"",
1620+
maxAllocatedDescs,dirname)));
1621+
1622+
/* Close excess kernel FDs. */
1623+
ReleaseLruFiles();
15561624

15571625
TryAgain:
15581626
if ((dir=opendir(dirname))!=NULL)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp