📄 fd.c
字号:
static voidInsert(File file){ Vfd *vfdP; Assert(file != 0); DO_DB(elog(LOG, "Insert %d (%s)", file, VfdCache[file].fileName)); DO_DB(_dump_lru()); vfdP = &VfdCache[file]; vfdP->lruMoreRecently = 0; vfdP->lruLessRecently = VfdCache[0].lruLessRecently; VfdCache[0].lruLessRecently = file; VfdCache[vfdP->lruLessRecently].lruMoreRecently = file; DO_DB(_dump_lru());}static intLruInsert(File file){ Vfd *vfdP; Assert(file != 0); DO_DB(elog(LOG, "LruInsert %d (%s)", file, VfdCache[file].fileName)); vfdP = &VfdCache[file]; if (FileIsNotOpen(file)) { while (nfile + numAllocatedFiles + numAllocatedDirs >= max_safe_fds) { if (!ReleaseLruFile()) break; } /* * The open could still fail for lack of file descriptors, eg due * to overall system file table being full. So, be prepared to * release another FD if necessary... */ vfdP->fd = BasicOpenFile(vfdP->fileName, vfdP->fileFlags, vfdP->fileMode); if (vfdP->fd < 0) { DO_DB(elog(LOG, "RE_OPEN FAILED: %d", errno)); return vfdP->fd; } else { DO_DB(elog(LOG, "RE_OPEN SUCCESS")); ++nfile; } /* seek to the right position */ if (vfdP->seekPos != 0L) { long returnValue; returnValue = (long) lseek(vfdP->fd, vfdP->seekPos, SEEK_SET); Assert(returnValue != -1L); } } /* * put it at the head of the Lru ring */ Insert(file); return 0;}static boolReleaseLruFile(void){ DO_DB(elog(LOG, "ReleaseLruFile. Opened %d", nfile)); if (nfile > 0) { /* * There are opened files and so there should be at least one used * vfd in the ring. */ Assert(VfdCache[0].lruMoreRecently != 0); LruDelete(VfdCache[0].lruMoreRecently); return true; /* freed a file */ } return false; /* no files available to free */}static FileAllocateVfd(void){ Index i; File file; DO_DB(elog(LOG, "AllocateVfd. Size %d", SizeVfdCache)); if (SizeVfdCache == 0) { /* initialize header entry first time through */ VfdCache = (Vfd *) malloc(sizeof(Vfd)); if (VfdCache == NULL) ereport(FATAL, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"))); MemSet((char *) &(VfdCache[0]), 0, sizeof(Vfd)); VfdCache->fd = VFD_CLOSED; SizeVfdCache = 1; /* * register proc-exit call to ensure temp files are dropped at * exit */ on_proc_exit(AtProcExit_Files, 0); } if (VfdCache[0].nextFree == 0) { /* * The free list is empty so it is time to increase the size of * the array. We choose to double it each time this happens. * However, there's not much point in starting *real* small. */ Size newCacheSize = SizeVfdCache * 2; Vfd *newVfdCache; if (newCacheSize < 32) newCacheSize = 32; /* * Be careful not to clobber VfdCache ptr if realloc fails. */ newVfdCache = (Vfd *) realloc(VfdCache, sizeof(Vfd) * newCacheSize); if (newVfdCache == NULL) ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"))); VfdCache = newVfdCache; /* * Initialize the new entries and link them into the free list. */ for (i = SizeVfdCache; i < newCacheSize; i++) { MemSet((char *) &(VfdCache[i]), 0, sizeof(Vfd)); VfdCache[i].nextFree = i + 1; VfdCache[i].fd = VFD_CLOSED; } VfdCache[newCacheSize - 1].nextFree = 0; VfdCache[0].nextFree = SizeVfdCache; /* * Record the new size */ SizeVfdCache = newCacheSize; } file = VfdCache[0].nextFree; VfdCache[0].nextFree = VfdCache[file].nextFree; return file;}static voidFreeVfd(File file){ Vfd *vfdP = &VfdCache[file]; DO_DB(elog(LOG, "FreeVfd: %d (%s)", file, vfdP->fileName ? vfdP->fileName : "")); if (vfdP->fileName != NULL) { free(vfdP->fileName); vfdP->fileName = NULL; } vfdP->fdstate = 0x0; vfdP->nextFree = VfdCache[0].nextFree; VfdCache[0].nextFree = file;}/* filepath() * Convert given pathname to absolute. * * Result is a palloc'd string. * * (Generally, this isn't actually necessary, considering that we * should be cd'd into the database directory. Presently it is only * necessary to do it in "bootstrap" mode. Maybe we should change * bootstrap mode to do the cd, and save a few cycles/bytes here.) */static char *filepath(const char *filename){ char *buf; /* Not an absolute path name? Then fill in with database path... */ if (!is_absolute_path(filename)) { buf = (char *) palloc(strlen(DatabasePath) + strlen(filename) + 2); sprintf(buf, "%s/%s", DatabasePath, filename); } else buf = pstrdup(filename);#ifdef FILEDEBUG printf("filepath: path is %s\n", buf);#endif return buf;}static intFileAccess(File file){ int returnValue; DO_DB(elog(LOG, "FileAccess %d (%s)", file, VfdCache[file].fileName)); /* * Is the file open? If not, open it and put it at the head of the * LRU ring (possibly closing the least recently used file to get an * FD). */ if (FileIsNotOpen(file)) { returnValue = LruInsert(file); if (returnValue != 0) return returnValue; } else if (VfdCache[0].lruLessRecently != file) { /* * 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); } return 0;}/* * Called when we get a shared invalidation message on some relation. */#ifdef NOT_USEDvoidFileInvalidate(File file){ Assert(FileIsValid(file)); if (!FileIsNotOpen(file)) LruDelete(file);}#endifstatic FilefileNameOpenFile(FileName fileName, int fileFlags, int fileMode){ char *fnamecopy; File file; Vfd *vfdP; DO_DB(elog(LOG, "fileNameOpenFile: %s %x %o", fileName, fileFlags, fileMode)); /* * 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]; while (nfile + numAllocatedFiles + numAllocatedDirs >= max_safe_fds) { if (!ReleaseLruFile()) break; } vfdP->fd = BasicOpenFile(fileName, fileFlags, fileMode); if (vfdP->fd < 0) { FreeVfd(file); free(fnamecopy); return -1; } ++nfile; DO_DB(elog(LOG, "fileNameOpenFile: success %d", vfdP->fd)); Insert(file); vfdP->fileName = fnamecopy; /* Saved flags are adjusted to be OK for re-opening file */ vfdP->fileFlags = fileFlags & ~(O_CREAT | O_TRUNC | O_EXCL); vfdP->fileMode = fileMode; vfdP->seekPos = 0; vfdP->fdstate = 0x0; return file;}/* * open a file in the database directory ($PGDATA/base/...) */FileFileNameOpenFile(FileName fileName, int fileFlags, int fileMode){ File fd; char *fname; fname = filepath(fileName); fd = fileNameOpenFile(fname, fileFlags, fileMode); pfree(fname); return fd;}/* * open a file in an arbitrary directory */FilePathNameOpenFile(FileName fileName, int fileFlags, int fileMode){ return fileNameOpenFile(fileName, fileFlags, fileMode);}/* * Open a temporary file that will disappear when we close it. * * This routine takes care of generating an appropriate tempfile name. * There's no need to pass in fileFlags or fileMode either, since only * one setting makes any sense for a temp file. * * interXact: if true, don't close the file at end-of-transaction. In * most cases, you don't want temporary files to outlive the transaction * that created them, so this should be false -- but if you need * "somewhat" temporary storage, this might be useful. In either case, * the file is removed when the File is explicitly closed. */FileOpenTemporaryFile(bool interXact){ char tempfilepath[MAXPGPATH]; File file; /* * Generate a tempfile name that should be unique within the current * database instance. */ snprintf(tempfilepath, sizeof(tempfilepath), "%s/%s%d.%ld", PG_TEMP_FILES_DIR, PG_TEMP_FILE_PREFIX, MyProcPid, tempFileCounter++); /* * Open the file. Note: we don't use O_EXCL, in case there is an * orphaned temp file that can be reused. */ file = FileNameOpenFile(tempfilepath, O_RDWR | O_CREAT | O_TRUNC | PG_BINARY, 0600); if (file <= 0) { char *dirpath; /* * We might need to create the pg_tempfiles subdirectory, if no * one has yet done so. * * Don't check for error from mkdir; it could fail if someone else * just did the same thing. If it doesn't work then we'll bomb * out on the second create attempt, instead. */ dirpath = filepath(PG_TEMP_FILES_DIR); mkdir(dirpath, S_IRWXU); pfree(dirpath); file = FileNameOpenFile(tempfilepath, O_RDWR | O_CREAT | O_TRUNC | PG_BINARY, 0600); if (file <= 0) elog(ERROR, "could not create temporary file \"%s\": %m", tempfilepath); } /* Mark it for deletion at close */ VfdCache[file].fdstate |= FD_TEMPORARY; /* Mark it for deletion at EOXact */ if (!interXact) VfdCache[file].fdstate |= FD_XACT_TEMPORARY; return file;}/* * close a file when done with it */voidFileClose(File file){ Vfd *vfdP; Assert(FileIsValid(file)); DO_DB(elog(LOG, "FileClose: %d (%s)", file, VfdCache[file].fileName)); vfdP = &VfdCache[file]; if (!FileIsNotOpen(file)) { /* remove the file from the lru ring */ Delete(file); /* close the file */ if (close(vfdP->fd)) elog(LOG, "failed to close \"%s\": %m", vfdP->fileName); --nfile; vfdP->fd = VFD_CLOSED; } /* * Delete the file if it was temporary */ if (vfdP->fdstate & FD_TEMPORARY) { /* reset flag so that die() interrupt won't cause problems */ vfdP->fdstate &= ~FD_TEMPORARY; if (unlink(vfdP->fileName)) elog(LOG, "failed to unlink \"%s\": %m", vfdP->fileName); } /* * Return the Vfd slot to the free list */ FreeVfd(file);}/* * close a file and forcibly delete the underlying Unix file */voidFileUnlink(File file)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -