⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fd.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 3 页
字号:
	{		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:				returnCode = FileAccess(file);				if (returnCode < 0)					return returnCode;				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));	returnCode = FileAccess(file);	if (returnCode < 0)		return returnCode;	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 (%s)",			   numAllocatedDescs, name));	/*	 * The test against MAX_ALLOCATED_DESCS 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 (numAllocatedDescs >= MAX_ALLOCATED_DESCS ||		numAllocatedDescs >= max_safe_fds - 1)		elog(ERROR, "too many private files demanded");TryAgain:	if ((file = fopen(name, mode)) != NULL)	{		AllocateDesc *desc = &allocatedDescs[numAllocatedDescs];		desc->kind = AllocateDescFile;		desc->desc.file = file;		desc->create_subid = GetCurrentSubTransactionId();		numAllocatedDescs++;		return desc->desc.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;}/* * Free an AllocateDesc of either type. * * The argument *must* point into the allocatedDescs[] array. */static intFreeDesc(AllocateDesc *desc){	int			result;	/* Close the underlying object */	switch (desc->kind)	{		case AllocateDescFile:			result = fclose(desc->desc.file);			break;		case AllocateDescDir:			result = closedir(desc->desc.dir);			break;		default:			elog(ERROR, "AllocateDesc kind not recognized");			result = 0;			/* keep compiler quiet */			break;	}	/* Compact storage in the allocatedDescs array */	numAllocatedDescs--;	*desc = allocatedDescs[numAllocatedDescs];	return result;}/* * Close a file returned by AllocateFile. * * Note we do not check fclose's return value --- it is up to the caller * to handle close errors. */intFreeFile(FILE *file){	int			i;	DO_DB(elog(LOG, "FreeFile: Allocated %d", numAllocatedDescs));	/* Remove file from list of allocated files, if it's present */	for (i = numAllocatedDescs; --i >= 0;)	{		AllocateDesc *desc = &allocatedDescs[i];		if (desc->kind == AllocateDescFile && desc->desc.file == file)			return FreeDesc(desc);	}	/* Only get here if someone passes us a file not in allocatedDescs */	elog(WARNING, "file passed to FreeFile was not obtained from AllocateFile");	return 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 (%s)",			   numAllocatedDescs, dirname));	/*	 * The test against MAX_ALLOCATED_DESCS prevents us from overflowing	 * allocatedDescs[]; the test against max_safe_fds prevents AllocateDir	 * from hogging every one of the available FDs, which'd lead to infinite	 * looping.	 */	if (numAllocatedDescs >= MAX_ALLOCATED_DESCS ||		numAllocatedDescs >= max_safe_fds - 1)		elog(ERROR, "too many private dirs demanded");TryAgain:	if ((dir = opendir(dirname)) != NULL)	{		AllocateDesc *desc = &allocatedDescs[numAllocatedDescs];		desc->kind = AllocateDescDir;		desc->desc.dir = dir;		desc->create_subid = GetCurrentSubTransactionId();		numAllocatedDescs++;		return desc->desc.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;}/* * Read a directory opened with AllocateDir, ereport'ing any error. * * This is easier to use than raw readdir() since it takes care of some * otherwise rather tedious and error-prone manipulation of errno.	Also, * if you are happy with a generic error message for AllocateDir failure, * you can just do * *		dir = AllocateDir(path); *		while ((dirent = ReadDir(dir, path)) != NULL) *			process dirent; *		FreeDir(path); * * since a NULL dir parameter is taken as indicating AllocateDir failed. * (Make sure errno hasn't been changed since AllocateDir if you use this * shortcut.) * * The pathname passed to AllocateDir must be passed to this routine too, * but it is only used for error reporting. */struct dirent *ReadDir(DIR *dir, const char *dirname){	struct dirent *dent;	/* Give a generic message for AllocateDir failure, if caller didn't */	if (dir == NULL)		ereport(ERROR,				(errcode_for_file_access(),				 errmsg("could not open directory \"%s\": %m",						dirname)));	errno = 0;	if ((dent = readdir(dir)) != NULL)		return dent;#ifdef WIN32	/*	 * This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but not in	 * released version	 */	if (GetLastError() == ERROR_NO_MORE_FILES)		errno = 0;#endif	if (errno)		ereport(ERROR,				(errcode_for_file_access(),				 errmsg("could not read directory \"%s\": %m",						dirname)));	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", numAllocatedDescs));	/* Remove dir from list of allocated dirs, if it's present */	for (i = numAllocatedDescs; --i >= 0;)	{		AllocateDesc *desc = &allocatedDescs[i];		if (desc->kind == AllocateDescDir && desc->desc.dir == dir)			return FreeDesc(desc);	}	/* Only get here if someone passes us a dir not in allocatedDescs */	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);		}	}}/* * AtEOSubXact_Files * * Take care of subtransaction commit/abort.  At abort, we close temp files * that the subtransaction may have opened.  At commit, we reassign the * files that were opened to the parent subtransaction. */voidAtEOSubXact_Files(bool isCommit, SubTransactionId mySubid,				  SubTransactionId parentSubid){	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_XACT_TEMPORARY) &&				VfdCache[i].create_subid == mySubid)			{				if (isCommit)					VfdCache[i].create_subid = parentSubid;				else if (VfdCache[i].fileName != NULL)					FileClose(i);			}		}	}	for (i = 0; i < numAllocatedDescs; i++)	{		if (allocatedDescs[i].create_subid == mySubid)		{			if (isCommit)				allocatedDescs[i].create_subid = parentSubid;			else			{				/* have to recheck the item after FreeDesc (ugly) */				FreeDesc(&allocatedDescs[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(int code, Datum arg){	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 (numAllocatedDescs > 0)		FreeDesc(&allocatedDescs[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		temp_path[MAXPGPATH];	DIR		   *db_dir;	struct dirent *db_de;	/*	 * Cycle through pgsql_tmp directories for all databases and remove old	 * temp files.	 */	db_dir = AllocateDir("base");	while ((db_de = ReadDir(db_dir, "base")) != NULL)	{		if (strcmp(db_de->d_name, ".") == 0 ||			strcmp(db_de->d_name, "..") == 0)			continue;		snprintf(temp_path, sizeof(temp_path), "base/%s/%s",				 db_de->d_name, PG_TEMP_FILES_DIR);		RemovePgTempFilesInDir(temp_path);	}	FreeDir(db_dir);	/*	 * In EXEC_BACKEND case there is a pgsql_tmp directory at the top level of	 * DataDir as well.	 */#ifdef EXEC_BACKEND	RemovePgTempFilesInDir(PG_TEMP_FILES_DIR);#endif}/* Process one pgsql_tmp directory for RemovePgTempFiles */static voidRemovePgTempFilesInDir(const char *tmpdirname){	DIR		   *temp_dir;	struct dirent *temp_de;	char		rm_path[MAXPGPATH];	temp_dir = AllocateDir(tmpdirname);	if (temp_dir == NULL)	{		/* anything except ENOENT is fishy */		if (errno != ENOENT)			elog(LOG,				 "could not open temporary-files directory \"%s\": %m",				 tmpdirname);		return;	}	while ((temp_de = ReadDir(temp_dir, tmpdirname)) != NULL)	{		if (strcmp(temp_de->d_name, ".") == 0 ||			strcmp(temp_de->d_name, "..") == 0)			continue;		snprintf(rm_path, sizeof(rm_path), "%s/%s",				 tmpdirname, temp_de->d_name);		if (strncmp(temp_de->d_name,					PG_TEMP_FILE_PREFIX,					strlen(PG_TEMP_FILE_PREFIX)) == 0)			unlink(rm_path);	/* note we ignore any error */		else			elog(LOG,				 "unexpected file found in temporary-files directory: \"%s\"",				 rm_path);	}	FreeDir(temp_dir);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -