📄 fd.c
字号:
{ Assert(FileIsValid(file)); DO_DB(elog(LOG, "FileUnlink: %d (%s)", file, VfdCache[file].fileName)); /* force FileClose to delete it */ VfdCache[file].fdstate |= FD_TEMPORARY; FileClose(file);}intFileRead(File file, char *buffer, int amount){ int returnCode; Assert(FileIsValid(file)); DO_DB(elog(LOG, "FileRead: %d (%s) %ld %d %p", file, VfdCache[file].fileName, VfdCache[file].seekPos, amount, buffer)); FileAccess(file); returnCode = read(VfdCache[file].fd, buffer, amount); if (returnCode > 0) VfdCache[file].seekPos += returnCode; else VfdCache[file].seekPos = FileUnknownPos; return returnCode;}intFileWrite(File file, char *buffer, int amount){ int returnCode; Assert(FileIsValid(file)); DO_DB(elog(LOG, "FileWrite: %d (%s) %ld %d %p", file, VfdCache[file].fileName, VfdCache[file].seekPos, amount, buffer)); FileAccess(file); errno = 0; returnCode = write(VfdCache[file].fd, buffer, amount); /* if write didn't set errno, assume problem is no disk space */ if (returnCode != amount && errno == 0) errno = ENOSPC; if (returnCode > 0) VfdCache[file].seekPos += returnCode; else VfdCache[file].seekPos = FileUnknownPos; return returnCode;}longFileSeek(File file, long offset, int whence){ Assert(FileIsValid(file)); DO_DB(elog(LOG, "FileSeek: %d (%s) %ld %ld %d", file, VfdCache[file].fileName, VfdCache[file].seekPos, offset, whence)); if (FileIsNotOpen(file)) { switch (whence) { case SEEK_SET: if (offset < 0) elog(ERROR, "invalid seek offset: %ld", offset); VfdCache[file].seekPos = offset; break; case SEEK_CUR: VfdCache[file].seekPos += offset; break; case SEEK_END: FileAccess(file); VfdCache[file].seekPos = lseek(VfdCache[file].fd, offset, whence); break; default: elog(ERROR, "invalid whence: %d", whence); break; } } else { switch (whence) { case SEEK_SET: if (offset < 0) elog(ERROR, "invalid seek offset: %ld", offset); if (VfdCache[file].seekPos != offset) VfdCache[file].seekPos = lseek(VfdCache[file].fd, offset, whence); break; case SEEK_CUR: if (offset != 0 || VfdCache[file].seekPos == FileUnknownPos) VfdCache[file].seekPos = lseek(VfdCache[file].fd, offset, whence); break; case SEEK_END: VfdCache[file].seekPos = lseek(VfdCache[file].fd, offset, whence); break; default: elog(ERROR, "invalid whence: %d", whence); break; } } return VfdCache[file].seekPos;}/* * XXX not actually used but here for completeness */#ifdef NOT_USEDlongFileTell(File file){ Assert(FileIsValid(file)); DO_DB(elog(LOG, "FileTell %d (%s)", file, VfdCache[file].fileName)); return VfdCache[file].seekPos;}#endifintFileTruncate(File file, long offset){ int returnCode; Assert(FileIsValid(file)); DO_DB(elog(LOG, "FileTruncate %d (%s)", file, VfdCache[file].fileName)); FileAccess(file); returnCode = ftruncate(VfdCache[file].fd, (size_t) offset); return returnCode;}/* * Routines that want to use stdio (ie, FILE*) should use AllocateFile * rather than plain fopen(). This lets fd.c deal with freeing FDs if * necessary to open the file. When done, call FreeFile rather than fclose. * * Note that files that will be open for any significant length of time * should NOT be handled this way, since they cannot share kernel file * descriptors with other files; there is grave risk of running out of FDs * if anyone locks down too many FDs. Most callers of this routine are * simply reading a config file that they will read and close immediately. * * fd.c will automatically close all files opened with AllocateFile at * transaction commit or abort; this prevents FD leakage if a routine * that calls AllocateFile is terminated prematurely by ereport(ERROR). * * Ideally this should be the *only* direct call of fopen() in the backend. */FILE *AllocateFile(char *name, char *mode){ FILE *file; DO_DB(elog(LOG, "AllocateFile: Allocated %d", numAllocatedFiles)); /* * The test against MAX_ALLOCATED_FILES prevents us from overflowing * allocatedFiles[]; the test against max_safe_fds prevents AllocateFile * from hogging every one of the available FDs, which'd lead to infinite * looping. */ if (numAllocatedFiles >= MAX_ALLOCATED_FILES || numAllocatedFiles + numAllocatedDirs >= max_safe_fds - 1) elog(ERROR, "too many private files demanded");TryAgain: if ((file = fopen(name, mode)) != NULL) { allocatedFiles[numAllocatedFiles] = file; numAllocatedFiles++; return file; } if (errno == EMFILE || errno == ENFILE) { int save_errno = errno; ereport(LOG, (errcode(ERRCODE_INSUFFICIENT_RESOURCES), errmsg("out of file descriptors: %m; release and retry"))); errno = 0; if (ReleaseLruFile()) goto TryAgain; errno = save_errno; } return NULL;}voidFreeFile(FILE *file){ int i; DO_DB(elog(LOG, "FreeFile: Allocated %d", numAllocatedFiles)); /* Remove file from list of allocated files, if it's present */ for (i = numAllocatedFiles; --i >= 0;) { if (allocatedFiles[i] == file) { numAllocatedFiles--; allocatedFiles[i] = allocatedFiles[numAllocatedFiles]; break; } } if (i < 0) elog(WARNING, "file passed to FreeFile was not obtained from AllocateFile"); fclose(file);}/* * Routines that want to use <dirent.h> (ie, DIR*) should use AllocateDir * rather than plain opendir(). This lets fd.c deal with freeing FDs if * necessary to open the directory, and with closing it after an elog. * When done, call FreeDir rather than closedir. * * Ideally this should be the *only* direct call of opendir() in the backend. */DIR *AllocateDir(const char *dirname){ DIR *dir; DO_DB(elog(LOG, "AllocateDir: Allocated %d", numAllocatedDirs)); /* * The test against MAX_ALLOCATED_DIRS prevents us from overflowing * allocatedDirs[]; the test against max_safe_fds prevents AllocateDir * from hogging every one of the available FDs, which'd lead to infinite * looping. */ if (numAllocatedDirs >= MAX_ALLOCATED_DIRS || numAllocatedDirs + numAllocatedFiles >= max_safe_fds - 1) elog(ERROR, "too many private dirs demanded");TryAgain: if ((dir = opendir(dirname)) != NULL) { allocatedDirs[numAllocatedDirs] = dir; numAllocatedDirs++; return dir; } if (errno == EMFILE || errno == ENFILE) { int save_errno = errno; ereport(LOG, (errcode(ERRCODE_INSUFFICIENT_RESOURCES), errmsg("out of file descriptors: %m; release and retry"))); errno = 0; if (ReleaseLruFile()) goto TryAgain; errno = save_errno; } return NULL;}/* * Close a directory opened with AllocateDir. * * Note we do not check closedir's return value --- it is up to the caller * to handle close errors. */intFreeDir(DIR *dir){ int i; DO_DB(elog(LOG, "FreeDir: Allocated %d", numAllocatedDirs)); /* Remove dir from list of allocated dirs, if it's present */ for (i = numAllocatedDirs; --i >= 0;) { if (allocatedDirs[i] == dir) { numAllocatedDirs--; allocatedDirs[i] = allocatedDirs[numAllocatedDirs]; break; } } if (i < 0) elog(WARNING, "dir passed to FreeDir was not obtained from AllocateDir"); return closedir(dir);}/* * closeAllVfds * * Force all VFDs into the physically-closed state, so that the fewest * possible number of kernel file descriptors are in use. There is no * change in the logical state of the VFDs. */voidcloseAllVfds(void){ Index i; if (SizeVfdCache > 0) { Assert(FileIsNotOpen(0)); /* Make sure ring not corrupted */ for (i = 1; i < SizeVfdCache; i++) { if (!FileIsNotOpen(i)) LruDelete(i); } }}/* * AtEOXact_Files * * This routine is called during transaction commit or abort (it doesn't * particularly care which). All still-open per-transaction temporary file * VFDs are closed, which also causes the underlying files to be * deleted. Furthermore, all "allocated" stdio files are closed. */voidAtEOXact_Files(void){ CleanupTempFiles(false);}/* * AtProcExit_Files * * on_proc_exit hook to clean up temp files during backend shutdown. * Here, we want to clean up *all* temp files including interXact ones. */static voidAtProcExit_Files(void){ CleanupTempFiles(true);}/* * Close temporary files and delete their underlying files. * * isProcExit: if true, this is being called as the backend process is * exiting. If that's the case, we should remove all temporary files; if * that's not the case, we are being called for transaction commit/abort * and should only remove transaction-local temp files. In either case, * also clean up "allocated" stdio files and dirs. */static voidCleanupTempFiles(bool isProcExit){ Index i; if (SizeVfdCache > 0) { Assert(FileIsNotOpen(0)); /* Make sure ring not corrupted */ for (i = 1; i < SizeVfdCache; i++) { unsigned short fdstate = VfdCache[i].fdstate; if ((fdstate & FD_TEMPORARY) && VfdCache[i].fileName != NULL) { /* * If we're in the process of exiting a backend process, * close all temporary files. Otherwise, only close * temporary files local to the current transaction. */ if (isProcExit || (fdstate & FD_XACT_TEMPORARY)) FileClose(i); } } } while (numAllocatedFiles > 0) FreeFile(allocatedFiles[0]); while (numAllocatedDirs > 0) FreeDir(allocatedDirs[0]);}/* * Remove temporary files left over from a prior postmaster session * * This should be called during postmaster startup. It will forcibly * remove any leftover files created by OpenTemporaryFile. * * NOTE: we could, but don't, call this during a post-backend-crash restart * cycle. The argument for not doing it is that someone might want to examine * the temp files for debugging purposes. This does however mean that * OpenTemporaryFile had better allow for collision with an existing temp * file name. */voidRemovePgTempFiles(void){ char db_path[MAXPGPATH]; char temp_path[MAXPGPATH]; char rm_path[MAXPGPATH]; DIR *db_dir; DIR *temp_dir; struct dirent *db_de; struct dirent *temp_de; /* * Cycle through pg_tempfiles for all databases and remove old temp * files. */ snprintf(db_path, sizeof(db_path), "%s/base", DataDir); if ((db_dir = AllocateDir(db_path)) != NULL) { while ((db_de = readdir(db_dir)) != NULL) { if (strcmp(db_de->d_name, ".") == 0 || strcmp(db_de->d_name, "..") == 0) continue; snprintf(temp_path, sizeof(temp_path), "%s/%s/%s", db_path, db_de->d_name, PG_TEMP_FILES_DIR); if ((temp_dir = AllocateDir(temp_path)) != NULL) { while ((temp_de = readdir(temp_dir)) != NULL) { if (strcmp(temp_de->d_name, ".") == 0 || strcmp(temp_de->d_name, "..") == 0) continue; snprintf(rm_path, sizeof(temp_path), "%s/%s/%s/%s", db_path, db_de->d_name, PG_TEMP_FILES_DIR, temp_de->d_name); if (strncmp(temp_de->d_name, PG_TEMP_FILE_PREFIX, strlen(PG_TEMP_FILE_PREFIX)) == 0) unlink(rm_path); else elog(LOG, "unexpected file found in temporary-files directory: \"%s\"", rm_path); } FreeDir(temp_dir); } } FreeDir(db_dir); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -