@@ -169,13 +169,7 @@ static intnfile = 0;
169
169
/*
170
170
* List of stdio FILEs and <dirent.h> DIRs opened with AllocateFile
171
171
* 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.
176
172
*/
177
- #define MAX_ALLOCATED_DESCS 32
178
-
179
173
typedef enum
180
174
{
181
175
AllocateDescFile ,
@@ -185,16 +179,17 @@ typedef enum
185
179
typedef struct
186
180
{
187
181
AllocateDescKind kind ;
182
+ SubTransactionId create_subid ;
188
183
union
189
184
{
190
185
FILE * file ;
191
186
DIR * dir ;
192
187
}desc ;
193
- SubTransactionId create_subid ;
194
188
}AllocateDesc ;
195
189
196
190
static int numAllocatedDescs = 0 ;
197
- static AllocateDesc allocatedDescs [MAX_ALLOCATED_DESCS ];
191
+ static int maxAllocatedDescs = 0 ;
192
+ static AllocateDesc * allocatedDescs = NULL ;
198
193
199
194
/*
200
195
* Number of temporary files opened during the current session;
@@ -220,6 +215,7 @@ static intnextTempTableSpace = 0;
220
215
* Insert - put a file at the front of the Lru ring
221
216
* LruInsert - put a file at the front of the Lru ring and open it
222
217
* 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
223
219
* AllocateVfd - grab a free (or new) file record (from VfdArray)
224
220
* FreeVfd - free a file record
225
221
*
@@ -247,11 +243,14 @@ static void LruDelete(File file);
247
243
static void Insert (File file );
248
244
static int LruInsert (File file );
249
245
static bool ReleaseLruFile (void );
246
+ static void ReleaseLruFiles (void );
250
247
static File AllocateVfd (void );
251
248
static void FreeVfd (File file );
252
249
253
250
static int FileAccess (File file );
254
251
static File OpenTemporaryFileInTablespace (Oid tblspcOid ,bool rejectError );
252
+ static bool reserveAllocatedDesc (void );
253
+ static int FreeDesc (AllocateDesc * desc );
255
254
static void AtProcExit_Files (int code ,Datum arg );
256
255
static void CleanupTempFiles (bool isProcExit );
257
256
static void RemovePgTempFilesInDir (const char * tmpdirname );
@@ -654,11 +653,8 @@ LruInsert(File file)
654
653
655
654
if (FileIsNotOpen (file ))
656
655
{
657
- while (nfile + numAllocatedDescs >=max_safe_fds )
658
- {
659
- if (!ReleaseLruFile ())
660
- break ;
661
- }
656
+ /* Close excess kernel FDs. */
657
+ ReleaseLruFiles ();
662
658
663
659
/*
664
660
* The open could still fail for lack of file descriptors, eg due to
@@ -697,6 +693,9 @@ LruInsert(File file)
697
693
return 0 ;
698
694
}
699
695
696
+ /*
697
+ * Release one kernel FD by closing the least-recently-used VFD.
698
+ */
700
699
static bool
701
700
ReleaseLruFile (void )
702
701
{
@@ -715,6 +714,20 @@ ReleaseLruFile(void)
715
714
return false;/* no files available to free */
716
715
}
717
716
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
+
718
731
static File
719
732
AllocateVfd (void )
720
733
{
@@ -868,11 +881,8 @@ PathNameOpenFile(FileName fileName, int fileFlags, int fileMode)
868
881
file = AllocateVfd ();
869
882
vfdP = & VfdCache [file ];
870
883
871
- while (nfile + numAllocatedDescs >=max_safe_fds )
872
- {
873
- if (!ReleaseLruFile ())
874
- break ;
875
- }
884
+ /* Close excess kernel FDs. */
885
+ ReleaseLruFiles ();
876
886
877
887
vfdP -> fd = BasicOpenFile (fileName ,fileFlags ,fileMode );
878
888
@@ -1402,6 +1412,66 @@ FilePathName(File file)
1402
1412
}
1403
1413
1404
1414
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
+
1405
1475
/*
1406
1476
* Routines that want to use stdio (ie, FILE*) should use AllocateFile
1407
1477
* rather than plain fopen(). This lets fd.c deal with freeing FDs if
@@ -1427,16 +1497,15 @@ AllocateFile(const char *name, const char *mode)
1427
1497
DO_DB (elog (LOG ,"AllocateFile: Allocated %d (%s)" ,
1428
1498
numAllocatedDescs ,name ));
1429
1499
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 ();
1440
1509
1441
1510
TryAgain :
1442
1511
if ((file = fopen (name ,mode ))!= NULL )
@@ -1543,16 +1612,15 @@ AllocateDir(const char *dirname)
1543
1612
DO_DB (elog (LOG ,"AllocateDir: Allocated %d (%s)" ,
1544
1613
numAllocatedDescs ,dirname ));
1545
1614
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 ();
1556
1624
1557
1625
TryAgain :
1558
1626
if ((dir = opendir (dirname ))!= NULL )