]> granicus.if.org Git - postgresql/blob - src/backend/storage/file/fd.c
Banish caddr_t (mostly), use Datum where appropriate.
[postgresql] / src / backend / storage / file / fd.c
1 /*-------------------------------------------------------------------------
2  *
3  * fd.c
4  *        Virtual file descriptor code.
5  *
6  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  * IDENTIFICATION
10  *        $Header: /cvsroot/pgsql/src/backend/storage/file/fd.c,v 1.64 2000/10/02 19:42:47 petere Exp $
11  *
12  * NOTES:
13  *
14  * This code manages a cache of 'virtual' file descriptors (VFDs).
15  * The server opens many file descriptors for a variety of reasons,
16  * including base tables, scratch files (e.g., sort and hash spool
17  * files), and random calls to C library routines like system(3); it
18  * is quite easy to exceed system limits on the number of open files a
19  * single process can have.  (This is around 256 on many modern
20  * operating systems, but can be as low as 32 on others.)
21  *
22  * VFDs are managed as an LRU pool, with actual OS file descriptors
23  * being opened and closed as needed.  Obviously, if a routine is
24  * opened using these interfaces, all subsequent operations must also
25  * be through these interfaces (the File type is not a real file
26  * descriptor).
27  *
28  * For this scheme to work, most (if not all) routines throughout the
29  * server should use these interfaces instead of calling the C library
30  * routines (e.g., open(2) and fopen(3)) themselves.  Otherwise, we
31  * may find ourselves short of real file descriptors anyway.
32  *
33  * This file used to contain a bunch of stuff to support RAID levels 0
34  * (jbod), 1 (duplex) and 5 (xor parity).  That stuff is all gone
35  * because the parallel query processing code that called it is all
36  * gone.  If you really need it you could get it from the original
37  * POSTGRES source.
38  *-------------------------------------------------------------------------
39  */
40
41 #include "postgres.h"
42
43 #include <sys/types.h>
44 #include <sys/file.h>
45 #include <sys/param.h>
46 #include <sys/stat.h>
47 #include <errno.h>
48 #include <unistd.h>
49 #include <fcntl.h>
50
51 #include "miscadmin.h"
52 #include "storage/fd.h"
53
54 /*
55  * Problem: Postgres does a system(ld...) to do dynamic loading.
56  * This will open several extra files in addition to those used by
57  * Postgres.  We need to guarantee that there are file descriptors free
58  * for ld to use.
59  *
60  * The current solution is to limit the number of file descriptors
61  * that this code will allocate at one time: it leaves RESERVE_FOR_LD free.
62  *
63  * (Even though most dynamic loaders now use dlopen(3) or the
64  * equivalent, the OS must still open several files to perform the
65  * dynamic loading.  Keep this here.)
66  */
67 #ifndef RESERVE_FOR_LD
68 #define RESERVE_FOR_LD  10
69 #endif
70
71 /*
72  * We need to ensure that we have at least some file descriptors
73  * available to postgreSQL after we've reserved the ones for LD,
74  * so we set that value here.
75  *
76  * I think 10 is an appropriate value so that's what it'll be
77  * for now.
78  */
79 #ifndef FD_MINFREE
80 #define FD_MINFREE 10
81 #endif
82
83 /* Debugging.... */
84
85 #ifdef FDDEBUG
86 #define DO_DB(A) A
87 #else
88 #define DO_DB(A)                                /* A */
89 #endif
90
91 #define VFD_CLOSED (-1)
92
93 #define FileIsValid(file) \
94         ((file) > 0 && (file) < (int) SizeVfdCache && VfdCache[file].fileName != NULL)
95
96 #define FileIsNotOpen(file) (VfdCache[file].fd == VFD_CLOSED)
97
98 #define FileUnknownPos (-1)
99
100 typedef struct vfd
101 {
102         signed short fd;                        /* current FD, or VFD_CLOSED if none */
103         unsigned short fdstate;         /* bitflags for VFD's state */
104
105 /* these are the assigned bits in fdstate: */
106 #define FD_DIRTY                (1 << 0)/* written to, but not yet fsync'd */
107 #define FD_TEMPORARY    (1 << 1)/* should be unlinked when closed */
108
109         File            nextFree;               /* link to next free VFD, if in freelist */
110         File            lruMoreRecently;/* doubly linked recency-of-use list */
111         File            lruLessRecently;
112         long            seekPos;                /* current logical file position */
113         char       *fileName;           /* name of file, or NULL for unused VFD */
114         /* NB: fileName is malloc'd, and must be free'd when closing the VFD */
115         int                     fileFlags;              /* open(2) flags for opening the file */
116         int                     fileMode;               /* mode to pass to open(2) */
117 } Vfd;
118
119 /*
120  * Virtual File Descriptor array pointer and size.      This grows as
121  * needed.      'File' values are indexes into this array.
122  * Note that VfdCache[0] is not a usable VFD, just a list header.
123  */
124 static Vfd *VfdCache;
125 static Size SizeVfdCache = 0;
126
127 /*
128  * Number of file descriptors known to be in use by VFD entries.
129  */
130 static int      nfile = 0;
131
132 /*
133  * List of stdio FILEs opened with AllocateFile.
134  *
135  * Since we don't want to encourage heavy use of AllocateFile, it seems
136  * OK to put a pretty small maximum limit on the number of simultaneously
137  * allocated files.
138  */
139 #define MAX_ALLOCATED_FILES  32
140
141 static int      numAllocatedFiles = 0;
142 static FILE *allocatedFiles[MAX_ALLOCATED_FILES];
143
144 /*
145  * Number of temporary files opened during the current transaction;
146  * this is used in generation of tempfile names.
147  */
148 static long tempFileCounter = 0;
149
150
151 /*--------------------
152  *
153  * Private Routines
154  *
155  * Delete                  - delete a file from the Lru ring
156  * LruDelete       - remove a file from the Lru ring and close its FD
157  * Insert                  - put a file at the front of the Lru ring
158  * LruInsert       - put a file at the front of the Lru ring and open it
159  * ReleaseLruFile  - Release an fd by closing the last entry in the Lru ring
160  * AllocateVfd     - grab a free (or new) file record (from VfdArray)
161  * FreeVfd                 - free a file record
162  *
163  * The Least Recently Used ring is a doubly linked list that begins and
164  * ends on element zero.  Element zero is special -- it doesn't represent
165  * a file and its "fd" field always == VFD_CLOSED.      Element zero is just an
166  * anchor that shows us the beginning/end of the ring.
167  * Only VFD elements that are currently really open (have an FD assigned) are
168  * in the Lru ring.  Elements that are "virtually" open can be recognized
169  * by having a non-null fileName field.
170  *
171  * example:
172  *
173  *         /--less----\                            /---------\
174  *         v               \                      v                       \
175  *       #0 --more---> LeastRecentlyUsed --more-\ \
176  *        ^\                                                                    | |
177  *         \\less--> MostRecentlyUsedFile       <---/ |
178  *              \more---/                                        \--less--/
179  *
180  *--------------------
181  */
182 static void Delete(File file);
183 static void LruDelete(File file);
184 static void Insert(File file);
185 static int      LruInsert(File file);
186 static bool ReleaseLruFile(void);
187 static File AllocateVfd(void);
188 static void FreeVfd(File file);
189
190 static int      FileAccess(File file);
191 static File fileNameOpenFile(FileName fileName, int fileFlags, int fileMode);
192 static char *filepath(char *filename);
193 static long pg_nofile(void);
194
195 /*
196  * pg_fsync --- same as fsync except does nothing if -F switch was given
197  */
198 int
199 pg_fsync(int fd)
200 {
201         if (enableFsync)
202                 return fsync(fd);
203         else
204                 return 0;
205 }
206
207 /*
208  * BasicOpenFile --- same as open(2) except can free other FDs if needed
209  *
210  * This is exported for use by places that really want a plain kernel FD,
211  * but need to be proof against running out of FDs.  Once an FD has been
212  * successfully returned, it is the caller's responsibility to ensure that
213  * it will not be leaked on elog()!  Most users should *not* call this
214  * routine directly, but instead use the VFD abstraction level, which
215  * provides protection against descriptor leaks as well as management of
216  * files that need to be open for more than a short period of time.
217  *
218  * Ideally this should be the *only* direct call of open() in the backend.
219  * In practice, the postmaster calls open() directly, and there are some
220  * direct open() calls done early in backend startup.  Those are OK since
221  * this module wouldn't have any open files to close at that point anyway.
222  */
223 int
224 BasicOpenFile(FileName fileName, int fileFlags, int fileMode)
225 {
226         int             fd;
227
228 tryAgain:
229         fd = open(fileName, fileFlags, fileMode);
230
231         if (fd >= 0)
232                 return fd;                              /* success! */
233
234         if (errno == EMFILE || errno == ENFILE)
235         {
236                 int             save_errno = errno;
237
238                 DO_DB(elog(DEBUG, "BasicOpenFile: not enough descs, retry, er= %d",
239                                    errno));
240                 errno = 0;
241                 if (ReleaseLruFile())
242                         goto tryAgain;
243                 errno = save_errno;
244         }
245
246         return -1;                                      /* failure */
247 }
248
249 /*
250  * pg_nofile: determine number of filedescriptors that fd.c is allowed to use
251  */
252 static long
253 pg_nofile(void)
254 {
255         static long no_files = 0;
256
257         if (no_files == 0)
258         {
259                 /* need do this calculation only once */
260 #ifndef HAVE_SYSCONF
261                 no_files = (long) NOFILE;
262 #else
263                 no_files = sysconf(_SC_OPEN_MAX);
264                 if (no_files == -1)
265                 {
266                         elog(DEBUG, "pg_nofile: Unable to get _SC_OPEN_MAX using sysconf(); using %d", NOFILE);
267                         no_files = (long) NOFILE;
268                 }
269 #endif
270
271                 if ((no_files - RESERVE_FOR_LD) < FD_MINFREE)
272                         elog(FATAL, "pg_nofile: insufficient File Descriptors in postmaster to start backend (%ld).\n"
273                                  "                   O/S allows %ld, Postmaster reserves %d, We need %d (MIN) after that.",
274                                  no_files - RESERVE_FOR_LD, no_files, RESERVE_FOR_LD, FD_MINFREE);
275
276                 no_files -= RESERVE_FOR_LD;
277         }
278
279         return no_files;
280 }
281
282 #if defined(FDDEBUG)
283
284 static void
285 _dump_lru(void)
286 {
287         int                     mru = VfdCache[0].lruLessRecently;
288         Vfd                *vfdP = &VfdCache[mru];
289         char            buf[2048];
290
291         sprintf(buf, "LRU: MOST %d ", mru);
292         while (mru != 0)
293         {
294                 mru = vfdP->lruLessRecently;
295                 vfdP = &VfdCache[mru];
296                 sprintf(buf + strlen(buf), "%d ", mru);
297         }
298         sprintf(buf + strlen(buf), "LEAST");
299         elog(DEBUG, buf);
300 }
301
302 #endif   /* FDDEBUG */
303
304 static void
305 Delete(File file)
306 {
307         Vfd                *vfdP;
308
309         Assert(file != 0);
310
311         DO_DB(elog(DEBUG, "Delete %d (%s)",
312                            file, VfdCache[file].fileName));
313         DO_DB(_dump_lru());
314
315         vfdP = &VfdCache[file];
316
317         VfdCache[vfdP->lruLessRecently].lruMoreRecently = vfdP->lruMoreRecently;
318         VfdCache[vfdP->lruMoreRecently].lruLessRecently = vfdP->lruLessRecently;
319
320         DO_DB(_dump_lru());
321 }
322
323 static void
324 LruDelete(File file)
325 {
326         Vfd                *vfdP;
327         int                     returnValue;
328
329         Assert(file != 0);
330
331         DO_DB(elog(DEBUG, "LruDelete %d (%s)",
332                            file, VfdCache[file].fileName));
333
334         vfdP = &VfdCache[file];
335
336         /* delete the vfd record from the LRU ring */
337         Delete(file);
338
339         /* save the seek position */
340         vfdP->seekPos = (long) lseek(vfdP->fd, 0L, SEEK_CUR);
341         Assert(vfdP->seekPos != -1);
342
343         /* if we have written to the file, sync it before closing */
344         if (vfdP->fdstate & FD_DIRTY)
345         {
346                 returnValue = pg_fsync(vfdP->fd);
347                 Assert(returnValue != -1);
348                 vfdP->fdstate &= ~FD_DIRTY;
349         }
350
351         /* close the file */
352         returnValue = close(vfdP->fd);
353         Assert(returnValue != -1);
354
355         --nfile;
356         vfdP->fd = VFD_CLOSED;
357 }
358
359 static void
360 Insert(File file)
361 {
362         Vfd                *vfdP;
363
364         Assert(file != 0);
365
366         DO_DB(elog(DEBUG, "Insert %d (%s)",
367                            file, VfdCache[file].fileName));
368         DO_DB(_dump_lru());
369
370         vfdP = &VfdCache[file];
371
372         vfdP->lruMoreRecently = 0;
373         vfdP->lruLessRecently = VfdCache[0].lruLessRecently;
374         VfdCache[0].lruLessRecently = file;
375         VfdCache[vfdP->lruLessRecently].lruMoreRecently = file;
376
377         DO_DB(_dump_lru());
378 }
379
380 static int
381 LruInsert(File file)
382 {
383         Vfd                *vfdP;
384         int                     returnValue;
385
386         Assert(file != 0);
387
388         DO_DB(elog(DEBUG, "LruInsert %d (%s)",
389                            file, VfdCache[file].fileName));
390
391         vfdP = &VfdCache[file];
392
393         if (FileIsNotOpen(file))
394         {
395                 while (nfile + numAllocatedFiles >= pg_nofile())
396                 {
397                         if (! ReleaseLruFile())
398                                 break;
399                 }
400
401                 /*
402                  * The open could still fail for lack of file descriptors, eg due
403                  * to overall system file table being full.  So, be prepared to
404                  * release another FD if necessary...
405                  */
406                 vfdP->fd = BasicOpenFile(vfdP->fileName, vfdP->fileFlags,
407                                                                  vfdP->fileMode);
408                 if (vfdP->fd < 0)
409                 {
410                         DO_DB(elog(DEBUG, "RE_OPEN FAILED: %d", errno));
411                         return vfdP->fd;
412                 }
413                 else
414                 {
415                         DO_DB(elog(DEBUG, "RE_OPEN SUCCESS"));
416                         ++nfile;
417                 }
418
419                 /* seek to the right position */
420                 if (vfdP->seekPos != 0L)
421                 {
422                         returnValue = lseek(vfdP->fd, vfdP->seekPos, SEEK_SET);
423                         Assert(returnValue != -1);
424                 }
425         }
426
427         /*
428          * put it at the head of the Lru ring
429          */
430
431         Insert(file);
432
433         return 0;
434 }
435
436 static bool
437 ReleaseLruFile(void)
438 {
439         DO_DB(elog(DEBUG, "ReleaseLruFile. Opened %d", nfile));
440
441         if (nfile > 0)
442         {
443                 /*
444                  * There are opened files and so there should be at least one used
445                  * vfd in the ring.
446                  */
447                 Assert(VfdCache[0].lruMoreRecently != 0);
448                 LruDelete(VfdCache[0].lruMoreRecently);
449                 return true;                    /* freed a file */
450         }
451         return false;                           /* no files available to free */
452 }
453
454 static File
455 AllocateVfd(void)
456 {
457         Index           i;
458         File            file;
459
460         DO_DB(elog(DEBUG, "AllocateVfd. Size %d", SizeVfdCache));
461
462         if (SizeVfdCache == 0)
463         {
464                 /* initialize header entry first time through */
465                 VfdCache = (Vfd *) malloc(sizeof(Vfd));
466                 Assert(VfdCache != NULL);
467                 MemSet((char *) &(VfdCache[0]), 0, sizeof(Vfd));
468                 VfdCache->fd = VFD_CLOSED;
469
470                 SizeVfdCache = 1;
471
472                 /*
473                  * register proc-exit call to ensure temp files are dropped at
474                  * exit
475                  */
476                 on_proc_exit(AtEOXact_Files, 0);
477         }
478
479         if (VfdCache[0].nextFree == 0)
480         {
481
482                 /*
483                  * The free list is empty so it is time to increase the size of
484                  * the array.  We choose to double it each time this happens.
485                  * However, there's not much point in starting *real* small.
486                  */
487                 Size            newCacheSize = SizeVfdCache * 2;
488
489                 if (newCacheSize < 32)
490                         newCacheSize = 32;
491
492                 VfdCache = (Vfd *) realloc(VfdCache, sizeof(Vfd) * newCacheSize);
493                 Assert(VfdCache != NULL);
494
495                 /*
496                  * Initialize the new entries and link them into the free list.
497                  */
498
499                 for (i = SizeVfdCache; i < newCacheSize; i++)
500                 {
501                         MemSet((char *) &(VfdCache[i]), 0, sizeof(Vfd));
502                         VfdCache[i].nextFree = i + 1;
503                         VfdCache[i].fd = VFD_CLOSED;
504                 }
505                 VfdCache[newCacheSize - 1].nextFree = 0;
506                 VfdCache[0].nextFree = SizeVfdCache;
507
508                 /*
509                  * Record the new size
510                  */
511
512                 SizeVfdCache = newCacheSize;
513         }
514
515         file = VfdCache[0].nextFree;
516
517         VfdCache[0].nextFree = VfdCache[file].nextFree;
518
519         return file;
520 }
521
522 static void
523 FreeVfd(File file)
524 {
525         Vfd                *vfdP = &VfdCache[file];
526
527         DO_DB(elog(DEBUG, "FreeVfd: %d (%s)",
528                            file, vfdP->fileName ? vfdP->fileName : ""));
529
530         if (vfdP->fileName != NULL)
531         {
532                 free(vfdP->fileName);
533                 vfdP->fileName = NULL;
534         }
535
536         vfdP->nextFree = VfdCache[0].nextFree;
537         VfdCache[0].nextFree = file;
538 }
539
540 /* filepath()
541  * Convert given pathname to absolute.
542  *
543  * (Generally, this isn't actually necessary, considering that we
544  * should be cd'd into the database directory.  Presently it is only
545  * necessary to do it in "bootstrap" mode.      Maybe we should change
546  * bootstrap mode to do the cd, and save a few cycles/bytes here.)
547  */
548 static char *
549 filepath(char *filename)
550 {
551         char       *buf;
552         int                     len;
553
554         /* Not an absolute path name? Then fill in with database path... */
555         if (*filename != SEP_CHAR)
556         {
557                 len = strlen(DatabasePath) + strlen(filename) + 2;
558                 buf = (char *) palloc(len);
559                 sprintf(buf, "%s%c%s", DatabasePath, SEP_CHAR, filename);
560         }
561         else
562         {
563                 buf = (char *) palloc(strlen(filename) + 1);
564                 strcpy(buf, filename);
565         }
566
567 #ifdef FILEDEBUG
568         printf("filepath: path is %s\n", buf);
569 #endif
570
571         return buf;
572 }
573
574 static int
575 FileAccess(File file)
576 {
577         int                     returnValue;
578
579         DO_DB(elog(DEBUG, "FileAccess %d (%s)",
580                            file, VfdCache[file].fileName));
581
582         /*
583          * Is the file open?  If not, open it and put it at the head of the
584          * LRU ring (possibly closing the least recently used file to get an
585          * FD).
586          */
587
588         if (FileIsNotOpen(file))
589         {
590                 returnValue = LruInsert(file);
591                 if (returnValue != 0)
592                         return returnValue;
593         }
594         else if (VfdCache[0].lruLessRecently != file)
595         {
596
597                 /*
598                  * We now know that the file is open and that it is not the last
599                  * one accessed, so we need to move it to the head of the Lru
600                  * ring.
601                  */
602
603                 Delete(file);
604                 Insert(file);
605         }
606
607         return 0;
608 }
609
610 /*
611  *      Called when we get a shared invalidation message on some relation.
612  */
613 #ifdef NOT_USED
614 void
615 FileInvalidate(File file)
616 {
617         Assert(FileIsValid(file));
618         if (!FileIsNotOpen(file))
619                 LruDelete(file);
620 }
621
622 #endif
623
624 static File
625 fileNameOpenFile(FileName fileName,
626                                  int fileFlags,
627                                  int fileMode)
628 {
629         File            file;
630         Vfd                *vfdP;
631
632         if (fileName == NULL)
633                 elog(ERROR, "fileNameOpenFile: NULL fname");
634
635         DO_DB(elog(DEBUG, "fileNameOpenFile: %s %x %o",
636                            fileName, fileFlags, fileMode));
637
638         file = AllocateVfd();
639         vfdP = &VfdCache[file];
640
641         while (nfile + numAllocatedFiles >= pg_nofile())
642         {
643                 if (! ReleaseLruFile())
644                         break;
645         }
646
647         vfdP->fd = BasicOpenFile(fileName, fileFlags, fileMode);
648
649         if (vfdP->fd < 0)
650         {
651                 FreeVfd(file);
652                 return -1;
653         }
654         ++nfile;
655         DO_DB(elog(DEBUG, "fileNameOpenFile: success %d",
656                            vfdP->fd));
657
658         Insert(file);
659
660         vfdP->fileName = malloc(strlen(fileName) + 1);
661         strcpy(vfdP->fileName, fileName);
662
663         vfdP->fileFlags = fileFlags & ~(O_TRUNC | O_EXCL);
664         vfdP->fileMode = fileMode;
665         vfdP->seekPos = 0;
666         vfdP->fdstate = 0x0;
667
668         return file;
669 }
670
671 /*
672  * open a file in the database directory ($PGDATA/base/...)
673  */
674 File
675 FileNameOpenFile(FileName fileName, int fileFlags, int fileMode)
676 {
677         File            fd;
678         char       *fname;
679
680         fname = filepath(fileName);
681         fd = fileNameOpenFile(fname, fileFlags, fileMode);
682         pfree(fname);
683         return fd;
684 }
685
686 /*
687  * open a file in an arbitrary directory
688  */
689 File
690 PathNameOpenFile(FileName fileName, int fileFlags, int fileMode)
691 {
692         return fileNameOpenFile(fileName, fileFlags, fileMode);
693 }
694
695 /*
696  * Open a temporary file that will disappear when we close it.
697  *
698  * This routine takes care of generating an appropriate tempfile name.
699  * There's no need to pass in fileFlags or fileMode either, since only
700  * one setting makes any sense for a temp file.
701  */
702 File
703 OpenTemporaryFile(void)
704 {
705         char            tempfilename[64];
706         File            file;
707
708         /*
709          * Generate a tempfile name that's unique within the current
710          * transaction
711          */
712         snprintf(tempfilename, sizeof(tempfilename),
713                          "pg_sorttemp%d.%ld", MyProcPid, tempFileCounter++);
714
715         /* Open the file */
716         file = FileNameOpenFile(tempfilename,
717                                                         O_RDWR | O_CREAT | O_TRUNC | PG_BINARY, 0600);
718         if (file <= 0)
719                 elog(ERROR, "Failed to create temporary file %s", tempfilename);
720
721         /* Mark it for deletion at close or EOXact */
722         VfdCache[file].fdstate |= FD_TEMPORARY;
723
724         return file;
725 }
726
727 /*
728  * close a file when done with it
729  */
730 void
731 FileClose(File file)
732 {
733         int                     returnValue;
734
735         Assert(FileIsValid(file));
736
737         DO_DB(elog(DEBUG, "FileClose: %d (%s)",
738                            file, VfdCache[file].fileName));
739
740         if (!FileIsNotOpen(file))
741         {
742
743                 /* remove the file from the lru ring */
744                 Delete(file);
745
746                 /* if we did any writes, sync the file before closing */
747                 if (VfdCache[file].fdstate & FD_DIRTY)
748                 {
749                         returnValue = pg_fsync(VfdCache[file].fd);
750                         Assert(returnValue != -1);
751                         VfdCache[file].fdstate &= ~FD_DIRTY;
752                 }
753
754                 /* close the file */
755                 returnValue = close(VfdCache[file].fd);
756                 Assert(returnValue != -1);
757
758                 --nfile;
759                 VfdCache[file].fd = VFD_CLOSED;
760         }
761
762         /*
763          * Delete the file if it was temporary
764          */
765         if (VfdCache[file].fdstate & FD_TEMPORARY)
766                 unlink(VfdCache[file].fileName);
767
768         /*
769          * Return the Vfd slot to the free list
770          */
771         FreeVfd(file);
772 }
773
774 /*
775  * close a file and forcibly delete the underlying Unix file
776  */
777 void
778 FileUnlink(File file)
779 {
780         Assert(FileIsValid(file));
781
782         DO_DB(elog(DEBUG, "FileUnlink: %d (%s)",
783                            file, VfdCache[file].fileName));
784
785         /* force FileClose to delete it */
786         VfdCache[file].fdstate |= FD_TEMPORARY;
787
788         FileClose(file);
789 }
790
791 int
792 FileRead(File file, char *buffer, int amount)
793 {
794         int                     returnCode;
795
796         Assert(FileIsValid(file));
797
798         DO_DB(elog(DEBUG, "FileRead: %d (%s) %d %p",
799                            file, VfdCache[file].fileName, amount, buffer));
800
801         FileAccess(file);
802         returnCode = read(VfdCache[file].fd, buffer, amount);
803         if (returnCode > 0)
804                 VfdCache[file].seekPos += returnCode;
805         else
806                 VfdCache[file].seekPos = FileUnknownPos;
807
808         return returnCode;
809 }
810
811 int
812 FileWrite(File file, char *buffer, int amount)
813 {
814         int                     returnCode;
815
816         Assert(FileIsValid(file));
817
818         DO_DB(elog(DEBUG, "FileWrite: %d (%s) %d %p",
819                            file, VfdCache[file].fileName, amount, buffer));
820
821         FileAccess(file);
822         returnCode = write(VfdCache[file].fd, buffer, amount);
823         if (returnCode > 0)
824         {
825                 VfdCache[file].seekPos += returnCode;
826                 /* mark the file as needing fsync */
827                 VfdCache[file].fdstate |= FD_DIRTY;
828         }
829         else
830                 VfdCache[file].seekPos = FileUnknownPos;
831
832         return returnCode;
833 }
834
835 long
836 FileSeek(File file, long offset, int whence)
837 {
838         Assert(FileIsValid(file));
839
840         DO_DB(elog(DEBUG, "FileSeek: %d (%s) %ld %d",
841                            file, VfdCache[file].fileName, offset, whence));
842
843         if (FileIsNotOpen(file))
844         {
845                 switch (whence)
846                 {
847                         case SEEK_SET:
848                                 if (offset < 0)
849                                         elog(ERROR, "FileSeek: invalid offset: %ld", offset);
850                                 VfdCache[file].seekPos = offset;
851                                 break;
852                         case SEEK_CUR:
853                                 VfdCache[file].seekPos += offset;
854                                 break;
855                         case SEEK_END:
856                                 FileAccess(file);
857                                 VfdCache[file].seekPos = lseek(VfdCache[file].fd, offset, whence);
858                                 break;
859                         default:
860                                 elog(ERROR, "FileSeek: invalid whence: %d", whence);
861                                 break;
862                 }
863         }
864         else
865         {
866                 switch (whence)
867                 {
868                         case SEEK_SET:
869                                 if (offset < 0)
870                                         elog(ERROR, "FileSeek: invalid offset: %ld", offset);
871                                 if (VfdCache[file].seekPos != offset)
872                                         VfdCache[file].seekPos = lseek(VfdCache[file].fd, offset, whence);
873                                 break;
874                         case SEEK_CUR:
875                                 if (offset != 0 || VfdCache[file].seekPos == FileUnknownPos)
876                                         VfdCache[file].seekPos = lseek(VfdCache[file].fd, offset, whence);
877                                 break;
878                         case SEEK_END:
879                                 VfdCache[file].seekPos = lseek(VfdCache[file].fd, offset, whence);
880                                 break;
881                         default:
882                                 elog(ERROR, "FileSeek: invalid whence: %d", whence);
883                                 break;
884                 }
885         }
886         return VfdCache[file].seekPos;
887 }
888
889 /*
890  * XXX not actually used but here for completeness
891  */
892 #ifdef NOT_USED
893 long
894 FileTell(File file)
895 {
896         Assert(FileIsValid(file));
897         DO_DB(elog(DEBUG, "FileTell %d (%s)",
898                            file, VfdCache[file].fileName));
899         return VfdCache[file].seekPos;
900 }
901
902 #endif
903
904 int
905 FileTruncate(File file, long offset)
906 {
907         int                     returnCode;
908
909         Assert(FileIsValid(file));
910
911         DO_DB(elog(DEBUG, "FileTruncate %d (%s)",
912                            file, VfdCache[file].fileName));
913
914         FileSync(file);
915         FileAccess(file);
916         returnCode = ftruncate(VfdCache[file].fd, (size_t) offset);
917         return returnCode;
918 }
919
920 /*
921  * FileSync --- if a file is marked as dirty, fsync it.
922  *
923  * The FD_DIRTY bit is slightly misnamed: it doesn't mean that we need to
924  * write the file, but that we *have* written it and need to execute an
925  * fsync() to ensure the changes are down on disk before we mark the current
926  * transaction committed.
927  *
928  * FD_DIRTY is set by FileWrite or by an explicit FileMarkDirty() call.
929  * It is cleared after successfully fsync'ing the file.  FileClose() will
930  * fsync a dirty File that is about to be closed, since there will be no
931  * other place to remember the need to fsync after the VFD is gone.
932  *
933  * Note that the DIRTY bit is logically associated with the actual disk file,
934  * not with any particular kernel FD we might have open for it.  We assume
935  * that fsync will force out any dirty buffers for that file, whether or not
936  * they were written through the FD being used for the fsync call --- they
937  * might even have been written by some other backend!
938  *
939  * Note also that LruDelete currently fsyncs a dirty file that it is about
940  * to close the kernel file descriptor for.  The idea there is to avoid
941  * having to re-open the kernel descriptor later.  But it's not real clear
942  * that this is a performance win; we could end up fsyncing the same file
943  * multiple times in a transaction, which would probably cost more time
944  * than is saved by avoiding an open() call.  This should be studied.
945  *
946  * This routine used to think it could skip the fsync if the file is
947  * physically closed, but that is now WRONG; see comments for FileMarkDirty.
948  */
949 int
950 FileSync(File file)
951 {
952         int                     returnCode;
953
954         Assert(FileIsValid(file));
955
956         if (!(VfdCache[file].fdstate & FD_DIRTY))
957         {
958                 /* Need not sync if file is not dirty. */
959                 returnCode = 0;
960         }
961         else if (!enableFsync)
962         {
963                 /* Don't force the file open if pg_fsync isn't gonna sync it. */
964                 returnCode = 0;
965                 VfdCache[file].fdstate &= ~FD_DIRTY;
966         }
967         else
968         {
969
970                 /*
971                  * We don't use FileAccess() because we don't want to force the
972                  * file to the front of the LRU ring; we aren't expecting to
973                  * access it again soon.
974                  */
975                 if (FileIsNotOpen(file))
976                 {
977                         returnCode = LruInsert(file);
978                         if (returnCode != 0)
979                                 return returnCode;
980                 }
981                 returnCode = pg_fsync(VfdCache[file].fd);
982                 if (returnCode == 0)
983                         VfdCache[file].fdstate &= ~FD_DIRTY;
984         }
985
986         return returnCode;
987 }
988
989 /*
990  * FileMarkDirty --- mark a file as needing fsync at transaction commit.
991  *
992  * Since FileWrite marks the file dirty, this routine is not needed in
993  * normal use.  It is called when the buffer manager detects that some other
994  * backend has written out a shared buffer that this backend dirtied (but
995  * didn't write) in the current xact.  In that scenario, we need to fsync
996  * the file before we can commit.  We cannot assume that the other backend
997  * has fsync'd the file yet; we need to do our own fsync to ensure that
998  * (a) the disk page is written and (b) this backend's commit is delayed
999  * until the write is complete.
1000  *
1001  * Note we are assuming that an fsync issued by this backend will write
1002  * kernel disk buffers that were dirtied by another backend.  Furthermore,
1003  * it doesn't matter whether we currently have the file physically open;
1004  * we must fsync even if we have to re-open the file to do it.
1005  */
1006 void
1007 FileMarkDirty(File file)
1008 {
1009         Assert(FileIsValid(file));
1010
1011         DO_DB(elog(DEBUG, "FileMarkDirty: %d (%s)",
1012                            file, VfdCache[file].fileName));
1013
1014         VfdCache[file].fdstate |= FD_DIRTY;
1015 }
1016
1017
1018 /*
1019  * Routines that want to use stdio (ie, FILE*) should use AllocateFile
1020  * rather than plain fopen().  This lets fd.c deal with freeing FDs if
1021  * necessary to open the file.  When done, call FreeFile rather than fclose.
1022  *
1023  * Note that files that will be open for any significant length of time
1024  * should NOT be handled this way, since they cannot share kernel file
1025  * descriptors with other files; there is grave risk of running out of FDs
1026  * if anyone locks down too many FDs.  Most callers of this routine are
1027  * simply reading a config file that they will read and close immediately.
1028  *
1029  * fd.c will automatically close all files opened with AllocateFile at
1030  * transaction commit or abort; this prevents FD leakage if a routine
1031  * that calls AllocateFile is terminated prematurely by elog(ERROR).
1032  *
1033  * Ideally this should be the *only* direct call of fopen() in the backend.
1034  */
1035
1036 FILE *
1037 AllocateFile(char *name, char *mode)
1038 {
1039         FILE       *file;
1040
1041         DO_DB(elog(DEBUG, "AllocateFile: Allocated %d", numAllocatedFiles));
1042
1043         if (numAllocatedFiles >= MAX_ALLOCATED_FILES)
1044                 elog(ERROR, "AllocateFile: too many private FDs demanded");
1045
1046 TryAgain:
1047         if ((file = fopen(name, mode)) != NULL)
1048         {
1049                 allocatedFiles[numAllocatedFiles++] = file;
1050                 return file;
1051         }
1052
1053         if (errno == EMFILE || errno == ENFILE)
1054         {
1055                 int             save_errno = errno;
1056
1057                 DO_DB(elog(DEBUG, "AllocateFile: not enough descs, retry, er= %d",
1058                                    errno));
1059                 errno = 0;
1060                 if (ReleaseLruFile())
1061                         goto TryAgain;
1062                 errno = save_errno;
1063         }
1064
1065         return NULL;
1066 }
1067
1068 void
1069 FreeFile(FILE *file)
1070 {
1071         int                     i;
1072
1073         DO_DB(elog(DEBUG, "FreeFile: Allocated %d", numAllocatedFiles));
1074
1075         /* Remove file from list of allocated files, if it's present */
1076         for (i = numAllocatedFiles; --i >= 0;)
1077         {
1078                 if (allocatedFiles[i] == file)
1079                 {
1080                         allocatedFiles[i] = allocatedFiles[--numAllocatedFiles];
1081                         break;
1082                 }
1083         }
1084         if (i < 0)
1085                 elog(NOTICE, "FreeFile: file was not obtained from AllocateFile");
1086
1087         fclose(file);
1088 }
1089
1090 /*
1091  * closeAllVfds
1092  *
1093  * Force all VFDs into the physically-closed state, so that the fewest
1094  * possible number of kernel file descriptors are in use.  There is no
1095  * change in the logical state of the VFDs.
1096  */
1097 void
1098 closeAllVfds(void)
1099 {
1100         Index           i;
1101
1102         if (SizeVfdCache > 0)
1103         {
1104                 Assert(FileIsNotOpen(0));               /* Make sure ring not corrupted */
1105                 for (i = 1; i < SizeVfdCache; i++)
1106                 {
1107                         if (!FileIsNotOpen(i))
1108                                 LruDelete(i);
1109                 }
1110         }
1111 }
1112
1113 /*
1114  * AtEOXact_Files
1115  *
1116  * This routine is called during transaction commit or abort or backend
1117  * exit (it doesn't particularly care which).  All still-open temporary-file
1118  * VFDs are closed, which also causes the underlying files to be deleted.
1119  * Furthermore, all "allocated" stdio files are closed.
1120  *
1121  * This routine is not involved in fsync'ing non-temporary files at xact
1122  * commit; that is done by FileSync under control of the buffer manager.
1123  * During a commit, that is done *before* control gets here.  If we still
1124  * have any needs-fsync bits set when we get here, we assume this is abort
1125  * and clear them.
1126  */
1127 void
1128 AtEOXact_Files(void)
1129 {
1130         Index           i;
1131
1132         if (SizeVfdCache > 0)
1133         {
1134                 Assert(FileIsNotOpen(0));               /* Make sure ring not corrupted */
1135                 for (i = 1; i < SizeVfdCache; i++)
1136                 {
1137                         if ((VfdCache[i].fdstate & FD_TEMPORARY) &&
1138                                 VfdCache[i].fileName != NULL)
1139                                 FileClose(i);
1140                         else
1141                                 VfdCache[i].fdstate &= ~FD_DIRTY;
1142                 }
1143         }
1144
1145         while (numAllocatedFiles > 0)
1146                 FreeFile(allocatedFiles[0]);
1147
1148         /*
1149          * Reset the tempfile name counter to 0; not really necessary, but
1150          * helps keep the names from growing unreasonably long.
1151          */
1152         tempFileCounter = 0;
1153 }