@@ -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- #define MAX_ALLOCATED_DESCS 32
178-
179173typedef enum
180174{
181175AllocateDescFile ,
@@ -185,16 +179,17 @@ typedef enum
185179typedef struct
186180{
187181AllocateDescKind kind ;
182+ SubTransactionId create_subid ;
188183union
189184{
190185FILE * file ;
191186DIR * dir ;
192187}desc ;
193- SubTransactionId create_subid ;
194188}AllocateDesc ;
195189
196190static int numAllocatedDescs = 0 ;
197- static AllocateDesc allocatedDescs [MAX_ALLOCATED_DESCS ];
191+ static int maxAllocatedDescs = 0 ;
192+ static AllocateDesc * 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);
247243static void Insert (File file );
248244static int LruInsert (File file );
249245static bool ReleaseLruFile (void );
246+ static void ReleaseLruFiles (void );
250247static File AllocateVfd (void );
251248static void FreeVfd (File file );
252249
253250static int FileAccess (File file );
254251static File OpenTemporaryFileInTablespace (Oid tblspcOid ,bool rejectError );
252+ static bool reserveAllocatedDesc (void );
253+ static int FreeDesc (AllocateDesc * desc );
255254static void AtProcExit_Files (int code ,Datum arg );
256255static void CleanupTempFiles (bool isProcExit );
257256static void RemovePgTempFilesInDir (const char * tmpdirname );
@@ -654,11 +653,8 @@ LruInsert(File file)
654653
655654if (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)
697693return 0 ;
698694}
699695
696+ /*
697+ * Release one kernel FD by closing the least-recently-used VFD.
698+ */
700699static bool
701700ReleaseLruFile (void )
702701{
@@ -715,6 +714,20 @@ ReleaseLruFile(void)
715714return 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+ static void
722+ ReleaseLruFiles (void )
723+ {
724+ while (nfile + numAllocatedDescs >=max_safe_fds )
725+ {
726+ if (!ReleaseLruFile ())
727+ break ;
728+ }
729+ }
730+
718731static File
719732AllocateVfd (void )
720733{
@@ -868,11 +881,8 @@ PathNameOpenFile(FileName fileName, int fileFlags, int fileMode)
868881file = AllocateVfd ();
869882vfdP = & 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
877887vfdP -> 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+ static bool
1420+ reserveAllocatedDesc (void )
1421+ {
1422+ AllocateDesc * newDescs ;
1423+ int newMax ;
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)
14271497DO_DB (elog (LOG ,"AllocateFile: Allocated %d (%s)" ,
14281498numAllocatedDescs ,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
14411510TryAgain :
14421511if ((file = fopen (name ,mode ))!= NULL )
@@ -1543,16 +1612,15 @@ AllocateDir(const char *dirname)
15431612DO_DB (elog (LOG ,"AllocateDir: Allocated %d (%s)" ,
15441613numAllocatedDescs ,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
15571625TryAgain :
15581626if ((dir = opendir (dirname ))!= NULL )