#define FD_DELETE_AT_CLOSE (1 << 0) /* T = delete when closed */
#define FD_CLOSE_AT_EOXACT (1 << 1) /* T = close at eoXact */
#define FD_TEMP_FILE_LIMIT (1 << 2) /* T = respect temp_file_limit */
+#define FD_NOT_IN_LRU (1 << 3) /* T = not in LRU */
typedef struct vfd
{
static void Insert(File file);
static int LruInsert(File file);
static bool ReleaseLruFile(void);
-static void ReleaseLruFiles(void);
static File AllocateVfd(void);
static void FreeVfd(File file);
* Release kernel FDs as needed to get under the max_safe_fds limit.
* After calling this, it's OK to try to open another file.
*/
-static void
+void
ReleaseLruFiles(void)
{
while (nfile + numAllocatedDescs >= max_safe_fds)
* We now know that the file is open and that it is not the last one
* accessed, so we need to move it to the head of the Lru ring.
*/
-
- Delete(file);
- Insert(file);
+ if (!(VfdCache[file].fdstate & FD_NOT_IN_LRU))
+ {
+ Delete(file);
+ Insert(file);
+ }
}
return 0;
return file;
}
+/*
+ * Open a File for a pre-existing file descriptor.
+ *
+ * Note that these files will not be closed in an LRU basis, therefore the
+ * caller is responsible for limiting the number of open file descriptors.
+ *
+ * The passed in name is purely for informational purposes.
+ */
+File
+FileOpenForFd(int fd, const char *fileName)
+{
+ char *fnamecopy;
+ File file;
+ Vfd *vfdP;
+
+ /*
+ * We need a malloc'd copy of the file name; fail cleanly if no room.
+ */
+ fnamecopy = strdup(fileName);
+ if (fnamecopy == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_OUT_OF_MEMORY),
+ errmsg("out of memory")));
+
+ file = AllocateVfd();
+ vfdP = &VfdCache[file];
+
+ /* Close excess kernel FDs. */
+ ReleaseLruFiles();
+
+ vfdP->fd = fd;
+ ++nfile;
+
+ DO_DB(elog(LOG, "FileOpenForFd: success %d/%d (%s)",
+ file, fd, fnamecopy));
+
+ /* NB: Explicitly not inserted into LRU! */
+
+ vfdP->fileName = fnamecopy;
+ /* Saved flags are adjusted to be OK for re-opening file */
+ vfdP->fileFlags = 0;
+ vfdP->fileMode = 0;
+ vfdP->seekPos = 0;
+ vfdP->fileSize = 0;
+ vfdP->fdstate = FD_NOT_IN_LRU;
+ vfdP->resowner = NULL;
+
+ return file;
+}
+
/*
* Create directory 'directory'. If necessary, create 'basedir', which must
* be the directory above it. This is designed for creating the top-level
vfdP->fd = VFD_CLOSED;
/* remove the file from the lru ring */
- Delete(file);
+ if (!(vfdP->fdstate & FD_NOT_IN_LRU))
+ {
+ vfdP->fdstate &= ~FD_NOT_IN_LRU;
+ Delete(file);
+ }
}
if (vfdP->fdstate & FD_TEMP_FILE_LIMIT)
/* Operations on virtual Files --- equivalent to Unix kernel file ops */
extern File PathNameOpenFile(const char *fileName, int fileFlags);
extern File PathNameOpenFilePerm(const char *fileName, int fileFlags, mode_t fileMode);
+extern File FileOpenForFd(int fd, const char *fileName);
extern File OpenTemporaryFile(bool interXact);
extern void FileClose(File file);
extern int FilePrefetch(File file, off_t offset, int amount, uint32 wait_event_info);
SubTransactionId parentSubid);
extern void RemovePgTempFiles(void);
extern bool looks_like_temp_rel_name(const char *name);
+extern void ReleaseLruFiles(void);
extern int pg_fsync(int fd);
extern int pg_fsync_no_writethrough(int fd);