@@ -179,13 +179,7 @@ static uint64 temporary_files_size = 0;
179
179
/*
180
180
* List of stdio FILEs and <dirent.h> DIRs opened with AllocateFile
181
181
* 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.
186
182
*/
187
- #define MAX_ALLOCATED_DESCS 32
188
-
189
183
typedef enum
190
184
{
191
185
AllocateDescFile ,
@@ -195,16 +189,17 @@ typedef enum
195
189
typedef struct
196
190
{
197
191
AllocateDescKind kind ;
192
+ SubTransactionId create_subid ;
198
193
union
199
194
{
200
195
FILE * file ;
201
196
DIR * dir ;
202
197
} desc ;
203
- SubTransactionId create_subid ;
204
198
} AllocateDesc ;
205
199
206
200
static int numAllocatedDescs = 0 ;
207
- static AllocateDesc allocatedDescs [MAX_ALLOCATED_DESCS ];
201
+ static int maxAllocatedDescs = 0 ;
202
+ static AllocateDesc * allocatedDescs = NULL ;
208
203
209
204
/*
210
205
* Number of temporary files opened during the current session;
@@ -230,6 +225,7 @@ static int nextTempTableSpace = 0;
230
225
* Insert - put a file at the front of the Lru ring
231
226
* LruInsert - put a file at the front of the Lru ring and open it
232
227
* 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
233
229
* AllocateVfd - grab a free (or new) file record (from VfdArray)
234
230
* FreeVfd - free a file record
235
231
*
@@ -257,11 +253,14 @@ static void LruDelete(File file);
257
253
static void Insert (File file );
258
254
static int LruInsert (File file );
259
255
static bool ReleaseLruFile (void );
256
+ static void ReleaseLruFiles (void );
260
257
static File AllocateVfd (void );
261
258
static void FreeVfd (File file );
262
259
263
260
static int FileAccess (File file );
264
261
static File OpenTemporaryFileInTablespace (Oid tblspcOid , bool rejectError );
262
+ static bool reserveAllocatedDesc (void );
263
+ static int FreeDesc (AllocateDesc * desc );
265
264
static void AtProcExit_Files (int code , Datum arg );
266
265
static void CleanupTempFiles (bool isProcExit );
267
266
static void RemovePgTempFilesInDir (const char * tmpdirname );
@@ -664,11 +663,8 @@ LruInsert(File file)
664
663
665
664
if (FileIsNotOpen (file ))
666
665
{
667
- while (nfile + numAllocatedDescs >= max_safe_fds )
668
- {
669
- if (!ReleaseLruFile ())
670
- break ;
671
- }
666
+ /* Close excess kernel FDs. */
667
+ ReleaseLruFiles ();
672
668
673
669
/*
674
670
* The open could still fail for lack of file descriptors, eg due to
@@ -707,6 +703,9 @@ LruInsert(File file)
707
703
return 0 ;
708
704
}
709
705
706
+ /*
707
+ * Release one kernel FD by closing the least-recently-used VFD.
708
+ */
710
709
static bool
711
710
ReleaseLruFile (void )
712
711
{
@@ -725,6 +724,20 @@ ReleaseLruFile(void)
725
724
return false; /* no files available to free */
726
725
}
727
726
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
+
728
741
static File
729
742
AllocateVfd (void )
730
743
{
@@ -878,11 +891,8 @@ PathNameOpenFile(FileName fileName, int fileFlags, int fileMode)
878
891
file = AllocateVfd ();
879
892
vfdP = & VfdCache [file ];
880
893
881
- while (nfile + numAllocatedDescs >= max_safe_fds )
882
- {
883
- if (!ReleaseLruFile ())
884
- break ;
885
- }
894
+ /* Close excess kernel FDs. */
895
+ ReleaseLruFiles ();
886
896
887
897
vfdP -> fd = BasicOpenFile (fileName , fileFlags , fileMode );
888
898
@@ -1461,6 +1471,66 @@ FilePathName(File file)
1461
1471
}
1462
1472
1463
1473
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
+
1464
1534
/*
1465
1535
* Routines that want to use stdio (ie, FILE*) should use AllocateFile
1466
1536
* rather than plain fopen(). This lets fd.c deal with freeing FDs if
@@ -1486,16 +1556,15 @@ AllocateFile(const char *name, const char *mode)
1486
1556
DO_DB (elog (LOG , "AllocateFile: Allocated %d (%s)" ,
1487
1557
numAllocatedDescs , name ));
1488
1558
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 ();
1499
1568
1500
1569
TryAgain :
1501
1570
if ((file = fopen (name , mode )) != NULL )
@@ -1602,16 +1671,15 @@ AllocateDir(const char *dirname)
1602
1671
DO_DB (elog (LOG , "AllocateDir: Allocated %d (%s)" ,
1603
1672
numAllocatedDescs , dirname ));
1604
1673
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 ();
1615
1683
1616
1684
TryAgain :
1617
1685
if ((dir = opendir (dirname )) != NULL )
0 commit comments