@@ -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- #define MAX_ALLOCATED_DESCS 32
188-
189183typedef enum
190184{
191185AllocateDescFile ,
@@ -195,16 +189,17 @@ typedef enum
195189typedef struct
196190{
197191AllocateDescKind kind ;
192+ SubTransactionId create_subid ;
198193union
199194{
200195FILE * file ;
201196DIR * dir ;
202197}desc ;
203- SubTransactionId create_subid ;
204198}AllocateDesc ;
205199
206200static int numAllocatedDescs = 0 ;
207- static AllocateDesc allocatedDescs [MAX_ALLOCATED_DESCS ];
201+ static int maxAllocatedDescs = 0 ;
202+ static AllocateDesc * 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);
257253static void Insert (File file );
258254static int LruInsert (File file );
259255static bool ReleaseLruFile (void );
256+ static void ReleaseLruFiles (void );
260257static File AllocateVfd (void );
261258static void FreeVfd (File file );
262259
263260static int FileAccess (File file );
264261static File OpenTemporaryFileInTablespace (Oid tblspcOid ,bool rejectError );
262+ static bool reserveAllocatedDesc (void );
263+ static int FreeDesc (AllocateDesc * desc );
265264static void AtProcExit_Files (int code ,Datum arg );
266265static void CleanupTempFiles (bool isProcExit );
267266static void RemovePgTempFilesInDir (const char * tmpdirname );
@@ -664,11 +663,8 @@ LruInsert(File file)
664663
665664if (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)
707703return 0 ;
708704}
709705
706+ /*
707+ * Release one kernel FD by closing the least-recently-used VFD.
708+ */
710709static bool
711710ReleaseLruFile (void )
712711{
@@ -725,6 +724,20 @@ ReleaseLruFile(void)
725724return 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+ static void
732+ ReleaseLruFiles (void )
733+ {
734+ while (nfile + numAllocatedDescs >=max_safe_fds )
735+ {
736+ if (!ReleaseLruFile ())
737+ break ;
738+ }
739+ }
740+
728741static File
729742AllocateVfd (void )
730743{
@@ -878,11 +891,8 @@ PathNameOpenFile(FileName fileName, int fileFlags, int fileMode)
878891file = AllocateVfd ();
879892vfdP = & 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
887897vfdP -> 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+ static bool
1479+ reserveAllocatedDesc (void )
1480+ {
1481+ AllocateDesc * newDescs ;
1482+ int newMax ;
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)
14861556DO_DB (elog (LOG ,"AllocateFile: Allocated %d (%s)" ,
14871557numAllocatedDescs ,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
15001569TryAgain :
15011570if ((file = fopen (name ,mode ))!= NULL )
@@ -1602,16 +1671,15 @@ AllocateDir(const char *dirname)
16021671DO_DB (elog (LOG ,"AllocateDir: Allocated %d (%s)" ,
16031672numAllocatedDescs ,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
16161684TryAgain :
16171685if ((dir = opendir (dirname ))!= NULL )