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