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

📄 fd.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 3 页
字号:
/* returns 0 on success, -1 on re-open failure (with errno set) */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 + numAllocatedDescs >= 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));	Assert(SizeVfdCache > 0);	/* InitFileAccess not called? */	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;}/* * make_database_relative() *		Prepend DatabasePath to the given file name. * * Result is a palloc'd string. */static char *make_database_relative(const char *filename){	char	   *buf;	Assert(!is_absolute_path(filename));	buf = (char *) palloc(strlen(DatabasePath) + strlen(filename) + 2);	sprintf(buf, "%s/%s", DatabasePath, filename);	return buf;}/* returns 0 on success, -1 on re-open failure (with errno set) */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);}#endif/* * open a file in an arbitrary directory * * NB: if the passed pathname is relative (which it usually is), * it will be interpreted relative to the process' working directory * (which should always be $PGDATA when this code is running). */FilePathNameOpenFile(FileName fileName, int fileFlags, int fileMode){	char	   *fnamecopy;	File		file;	Vfd		   *vfdP;	DO_DB(elog(LOG, "PathNameOpenFile: %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 + numAllocatedDescs >= 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, "PathNameOpenFile: 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/DIROID/) * * The passed name MUST be a relative path.  Effectively, this * prepends DatabasePath to it and then acts like PathNameOpenFile. */FileFileNameOpenFile(FileName fileName, int fileFlags, int fileMode){	File		fd;	char	   *fname;	fname = make_database_relative(fileName);	fd = PathNameOpenFile(fname, fileFlags, fileMode);	pfree(fname);	return fd;}/* * 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 = make_database_relative(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;		VfdCache[file].create_subid = GetCurrentSubTransactionId();	}	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(ERROR, "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){	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));	returnCode = FileAccess(file);	if (returnCode < 0)		return returnCode;retry:	returnCode = read(VfdCache[file].fd, buffer, amount);	if (returnCode >= 0)		VfdCache[file].seekPos += returnCode;	else	{		/*		 * Windows may run out of kernel buffers and return "Insufficient		 * system resources" error.  Wait a bit and retry to solve it.		 *		 * It is rumored that EINTR is also possible on some Unix filesystems,		 * in which case immediate retry is indicated.		 */#ifdef WIN32		DWORD error = GetLastError();		switch (error)		{			case ERROR_NO_SYSTEM_RESOURCES:				pg_usleep(1000L);				errno = EINTR;				break;			default:				_dosmaperr(error);				break;		}#endif		/* OK to retry if interrupted */		if (errno == EINTR)			goto retry;		/* Trouble, so assume we don't know the file position anymore */		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));	returnCode = FileAccess(file);	if (returnCode < 0)		return returnCode;retry:	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	{		/*		 * See comments in FileRead()		 */#ifdef WIN32		DWORD error = GetLastError();		switch (error)		{			case ERROR_NO_SYSTEM_RESOURCES:				pg_usleep(1000L);				errno = EINTR;				break;			default:				_dosmaperr(error);				break;		}#endif		/* OK to retry if interrupted */		if (errno == EINTR)			goto retry;		/* Trouble, so assume we don't know the file position anymore */		VfdCache[file].seekPos = FileUnknownPos;	}	return returnCode;}intFileSync(File file){	int			returnCode;	Assert(FileIsValid(file));	DO_DB(elog(LOG, "FileSync: %d (%s)",			   file, VfdCache[file].fileName));	returnCode = FileAccess(file);	if (returnCode < 0)		return returnCode;	return pg_fsync(VfdCache[file].fd);}longFileSeek(File file, long offset, int whence){	int			returnCode;	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))

⌨️ 快捷键说明

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