|
7 | 7 | * Portions Copyright (c) 1994, Regents of the University of California |
8 | 8 | * |
9 | 9 | * IDENTIFICATION |
10 | | - * $PostgreSQL: pgsql/src/backend/storage/file/fd.c,v 1.106 2004/01/26 22:35:32 tgl Exp $ |
| 10 | + * $PostgreSQL: pgsql/src/backend/storage/file/fd.c,v 1.107 2004/02/23 20:45:59 tgl Exp $ |
11 | 11 | * |
12 | 12 | * NOTES: |
13 | 13 | * |
|
54 | 54 |
|
55 | 55 |
|
56 | 56 | /* |
57 | | - * Problem: Postgres does a system(ld...) to do dynamic loading. |
58 | | - * This will open several extra files in addition to those used by |
59 | | - * Postgres. We need to guarantee that there are file descriptors free |
60 | | - * for ld to use. |
| 57 | + * We must leave some file descriptors free for system(), the dynamic loader, |
| 58 | + * and other code that tries to open files without consulting fd.c. This |
| 59 | + * is the number left free. (While we can be pretty sure we won't get |
| 60 | + * EMFILE, there's never any guarantee that we won't get ENFILE due to |
| 61 | + * other processes chewing up FDs. So it's a bad idea to try to open files |
| 62 | + * without consulting fd.c. Nonetheless we cannot control all code.) |
61 | 63 | * |
62 | | - * The current solution is to limit the number of file descriptors |
63 | | - * that this code will allocate at one time: it leaves RESERVE_FOR_LD free. |
64 | | - * |
65 | | - * (Even though most dynamic loaders now use dlopen(3) or the |
66 | | - * equivalent, the OS must still open several files to perform the |
67 | | - * dynamic loading. And stdin/stdout/stderr count too. Keep this here.) |
| 64 | + * Because this is just a fixed setting, we are effectively assuming that |
| 65 | + * no such code will leave FDs open over the long term; otherwise the slop |
| 66 | + * is likely to be insufficient. Note in particular that we expect that |
| 67 | + * loading a shared library does not result in any permanent increase in |
| 68 | + * the number of open files. (This appears to be true on most if not |
| 69 | + * all platforms as of Feb 2004.) |
68 | 70 | */ |
69 | | -#ifndef RESERVE_FOR_LD |
70 | | -#define RESERVE_FOR_LD 10 |
71 | | -#endif |
| 71 | +#define NUM_RESERVED_FDS 10 |
72 | 72 |
|
73 | 73 | /* |
74 | | - * We need to ensure that we have at least some file descriptors |
75 | | - * available to postgreSQL after we've reserved the ones for LD, |
76 | | - * so we set that value here. |
77 | | - * |
78 | | - * I think 10 is an appropriate value so that's what it'll be |
79 | | - * for now. |
| 74 | + * If we have fewer than this many usable FDs after allowing for the reserved |
| 75 | + * ones, choke. |
80 | 76 | */ |
81 | | -#ifndef FD_MINFREE |
82 | | -#define FD_MINFREE 10 |
83 | | -#endif |
| 77 | +#define FD_MINFREE 10 |
| 78 | + |
84 | 79 |
|
85 | 80 | /* |
86 | | - * A number of platforms return values for sysconf(_SC_OPEN_MAX) that are |
87 | | - * far beyond what they can really support. This GUC parameter limits what |
88 | | - * we will believe. |
| 81 | + * A number of platforms allow individual processes to open many more files |
| 82 | + * than they can really support when *many* processes do the same thing. |
| 83 | + * This GUC parameter lets the DBA limit max_safe_fds to something less than |
| 84 | + * what the postmaster's initial probe suggests will work. |
89 | 85 | */ |
90 | 86 | int max_files_per_process = 1000; |
91 | 87 |
|
| 88 | +/* |
| 89 | + * Maximum number of file descriptors to open for either VFD entries or |
| 90 | + * AllocateFile files. This is initialized to a conservative value, and |
| 91 | + * remains that way indefinitely in bootstrap or standalone-backend cases. |
| 92 | + * In normal postmaster operation, the postmaster calls set_max_safe_fds() |
| 93 | + * late in initialization to update the value, and that value is then |
| 94 | + * inherited by forked subprocesses. |
| 95 | + * |
| 96 | + * Note: the value of max_files_per_process is taken into account while |
| 97 | + * setting this variable, and so need not be tested separately. |
| 98 | + */ |
| 99 | +static int max_safe_fds = 32; /* default if not changed */ |
| 100 | + |
92 | 101 |
|
93 | 102 | /* Debugging.... */ |
94 | 103 |
|
@@ -199,7 +208,6 @@ static void FreeVfd(File file); |
199 | 208 | static int FileAccess(File file); |
200 | 209 | static File fileNameOpenFile(FileName fileName, int fileFlags, int fileMode); |
201 | 210 | static char *filepath(const char *filename); |
202 | | -static long pg_nofile(void); |
203 | 211 | static void AtProcExit_Files(int code, Datum arg); |
204 | 212 | static void CleanupTempFiles(bool isProcExit); |
205 | 213 |
|
@@ -236,6 +244,105 @@ pg_fdatasync(int fd) |
236 | 244 | return 0; |
237 | 245 | } |
238 | 246 |
|
| 247 | +/* |
| 248 | + * count_usable_fds --- count how many FDs the system will let us open, |
| 249 | + * and estimate how many are already open. |
| 250 | + * |
| 251 | + * We assume stdin (FD 0) is available for dup'ing |
| 252 | + */ |
| 253 | +static void |
| 254 | +count_usable_fds(int *usable_fds, int *already_open) |
| 255 | +{ |
| 256 | + int *fd; |
| 257 | + int size; |
| 258 | + int used = 0; |
| 259 | + int highestfd = 0; |
| 260 | + int j; |
| 261 | + |
| 262 | + size = 1024; |
| 263 | + fd = (int *) palloc(size * sizeof(int)); |
| 264 | + |
| 265 | + /* dup until failure ... */ |
| 266 | + for (;;) |
| 267 | + { |
| 268 | + int thisfd; |
| 269 | + |
| 270 | + thisfd = dup(0); |
| 271 | + if (thisfd < 0) |
| 272 | + { |
| 273 | + /* Expect EMFILE or ENFILE, else it's fishy */ |
| 274 | + if (errno != EMFILE && errno != ENFILE) |
| 275 | + elog(WARNING, "dup(0) failed after %d successes: %m", used); |
| 276 | + break; |
| 277 | + } |
| 278 | + |
| 279 | + if (used >= size) |
| 280 | + { |
| 281 | + size *= 2; |
| 282 | + fd = (int *) repalloc(fd, size * sizeof(int)); |
| 283 | + } |
| 284 | + fd[used++] = thisfd; |
| 285 | + |
| 286 | + if (highestfd < thisfd) |
| 287 | + highestfd = thisfd; |
| 288 | + } |
| 289 | + |
| 290 | + /* release the files we opened */ |
| 291 | + for (j = 0; j < used; j++) |
| 292 | + close(fd[j]); |
| 293 | + |
| 294 | + pfree(fd); |
| 295 | + |
| 296 | + /* |
| 297 | + * Return results. usable_fds is just the number of successful dups. |
| 298 | + * We assume that the system limit is highestfd+1 (remember 0 is a legal |
| 299 | + * FD number) and so already_open is highestfd+1 - usable_fds. |
| 300 | + */ |
| 301 | + *usable_fds = used; |
| 302 | + *already_open = highestfd+1 - used; |
| 303 | +} |
| 304 | + |
| 305 | +/* |
| 306 | + * set_max_safe_fds |
| 307 | + * Determine number of filedescriptors that fd.c is allowed to use |
| 308 | + */ |
| 309 | +void |
| 310 | +set_max_safe_fds(void) |
| 311 | +{ |
| 312 | + int usable_fds; |
| 313 | + int already_open; |
| 314 | + |
| 315 | + /* |
| 316 | + * We want to set max_safe_fds to |
| 317 | + * MIN(usable_fds, max_files_per_process - already_open) |
| 318 | + * less the slop factor for files that are opened without consulting |
| 319 | + * fd.c. This ensures that we won't exceed either max_files_per_process |
| 320 | + * or the experimentally-determined EMFILE limit. |
| 321 | + */ |
| 322 | + count_usable_fds(&usable_fds, &already_open); |
| 323 | + |
| 324 | + max_safe_fds = Min(usable_fds, max_files_per_process - already_open); |
| 325 | + |
| 326 | + /* |
| 327 | + * Take off the FDs reserved for system() etc. |
| 328 | + */ |
| 329 | + max_safe_fds -= NUM_RESERVED_FDS; |
| 330 | + |
| 331 | + /* |
| 332 | + * Make sure we still have enough to get by. |
| 333 | + */ |
| 334 | + if (max_safe_fds < FD_MINFREE) |
| 335 | + ereport(FATAL, |
| 336 | + (errcode(ERRCODE_INSUFFICIENT_RESOURCES), |
| 337 | + errmsg("insufficient file descriptors available to start server process"), |
| 338 | + errdetail("System allows %d, we need at least %d.", |
| 339 | + max_safe_fds + NUM_RESERVED_FDS, |
| 340 | + FD_MINFREE + NUM_RESERVED_FDS))); |
| 341 | + |
| 342 | + elog(DEBUG2, "max_safe_fds = %d, usable_fds = %d, already_open = %d", |
| 343 | + max_safe_fds, usable_fds, already_open); |
| 344 | +} |
| 345 | + |
239 | 346 | /* |
240 | 347 | * BasicOpenFile --- same as open(2) except can free other FDs if needed |
241 | 348 | * |
@@ -279,63 +386,6 @@ BasicOpenFile(FileName fileName, int fileFlags, int fileMode) |
279 | 386 | return -1; /* failure */ |
280 | 387 | } |
281 | 388 |
|
282 | | -/* |
283 | | - * pg_nofile: determine number of filedescriptors that fd.c is allowed to use |
284 | | - */ |
285 | | -static long |
286 | | -pg_nofile(void) |
287 | | -{ |
288 | | - static long no_files = 0; |
289 | | - |
290 | | - /* need do this calculation only once */ |
291 | | - if (no_files == 0) |
292 | | - { |
293 | | - /* |
294 | | - * Ask the system what its files-per-process limit is. |
295 | | - */ |
296 | | -#ifdef HAVE_SYSCONF |
297 | | - no_files = sysconf(_SC_OPEN_MAX); |
298 | | - if (no_files <= 0) |
299 | | - { |
300 | | -#ifdef NOFILE |
301 | | - no_files = (long) NOFILE; |
302 | | -#else |
303 | | - no_files = (long) max_files_per_process; |
304 | | -#endif |
305 | | - elog(LOG, "sysconf(_SC_OPEN_MAX) failed; using %ld", |
306 | | - no_files); |
307 | | - } |
308 | | -#else /* !HAVE_SYSCONF */ |
309 | | -#ifdef NOFILE |
310 | | - no_files = (long) NOFILE; |
311 | | -#else |
312 | | - no_files = (long) max_files_per_process; |
313 | | -#endif |
314 | | -#endif /* HAVE_SYSCONF */ |
315 | | - |
316 | | - /* |
317 | | - * Some platforms return hopelessly optimistic values. Apply a |
318 | | - * configurable upper limit. |
319 | | - */ |
320 | | - if (no_files > (long) max_files_per_process) |
321 | | - no_files = (long) max_files_per_process; |
322 | | - |
323 | | - /* |
324 | | - * Make sure we have enough to get by after reserving some for LD. |
325 | | - */ |
326 | | - if ((no_files - RESERVE_FOR_LD) < FD_MINFREE) |
327 | | - ereport(FATAL, |
328 | | - (errcode(ERRCODE_INSUFFICIENT_RESOURCES), |
329 | | - errmsg("insufficient file descriptors available to start server process"), |
330 | | - errdetail("System allows %ld, we need at least %d.", |
331 | | - no_files, RESERVE_FOR_LD + FD_MINFREE))); |
332 | | - |
333 | | - no_files -= RESERVE_FOR_LD; |
334 | | - } |
335 | | - |
336 | | - return no_files; |
337 | | -} |
338 | | - |
339 | 389 | #if defined(FDDEBUG) |
340 | 390 |
|
341 | 391 | static void |
@@ -439,7 +489,7 @@ LruInsert(File file) |
439 | 489 |
|
440 | 490 | if (FileIsNotOpen(file)) |
441 | 491 | { |
442 | | - while (nfile + numAllocatedFiles >= pg_nofile()) |
| 492 | + while (nfile + numAllocatedFiles >= max_safe_fds) |
443 | 493 | { |
444 | 494 | if (!ReleaseLruFile()) |
445 | 495 | break; |
@@ -698,7 +748,7 @@ fileNameOpenFile(FileName fileName, |
698 | 748 | file = AllocateVfd(); |
699 | 749 | vfdP = &VfdCache[file]; |
700 | 750 |
|
701 | | - while (nfile + numAllocatedFiles >= pg_nofile()) |
| 751 | + while (nfile + numAllocatedFiles >= max_safe_fds) |
702 | 752 | { |
703 | 753 | if (!ReleaseLruFile()) |
704 | 754 | break; |
@@ -1042,7 +1092,14 @@ AllocateFile(char *name, char *mode) |
1042 | 1092 |
|
1043 | 1093 | DO_DB(elog(LOG, "AllocateFile: Allocated %d", numAllocatedFiles)); |
1044 | 1094 |
|
1045 | | - if (numAllocatedFiles >= MAX_ALLOCATED_FILES) |
| 1095 | + /* |
| 1096 | + * The test against MAX_ALLOCATED_FILES prevents us from overflowing |
| 1097 | + * allocatedFiles[]; the test against max_safe_fds prevents AllocateFile |
| 1098 | + * from hogging every one of the available FDs, which'd lead to infinite |
| 1099 | + * looping. |
| 1100 | + */ |
| 1101 | + if (numAllocatedFiles >= MAX_ALLOCATED_FILES || |
| 1102 | + numAllocatedFiles >= max_safe_fds - 1) |
1046 | 1103 | elog(ERROR, "too many private FDs demanded"); |
1047 | 1104 |
|
1048 | 1105 | TryAgain: |
|
0 commit comments