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

📄 fd.c

📁 postgresql8.3.4源码,开源数据库
💻 C
📖 第 1 页 / 共 3 页
字号:
		 * 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 %lu", 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;}/* 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 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){	File		file = 0;	/*	 * If some temp tablespace(s) have been given to us, try to use the next	 * one.  If a given tablespace can't be found, we silently fall back to	 * the database's default tablespace.	 *	 * BUT: if the temp file is slated to outlive the current transaction,	 * force it into the database's default tablespace, so that it will not	 * pose a threat to possible tablespace drop attempts.	 */	if (numTempTableSpaces > 0 && !interXact)	{		Oid			tblspcOid = GetNextTempTableSpace();		if (OidIsValid(tblspcOid))			file = OpenTemporaryFileInTablespace(tblspcOid, false);	}	/*	 * If not, or if tablespace is bad, create in database's default	 * tablespace.	MyDatabaseTableSpace should normally be set before we get	 * here, but just in case it isn't, fall back to pg_default tablespace.	 */	if (file <= 0)		file = OpenTemporaryFileInTablespace(MyDatabaseTableSpace ?											 MyDatabaseTableSpace :											 DEFAULTTABLESPACE_OID,											 true);	/* 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;}/* * Open a temporary file in a specific tablespace. * Subroutine for OpenTemporaryFile, which see for details. */static FileOpenTemporaryFileInTablespace(Oid tblspcOid, bool rejectError){	char		tempdirpath[MAXPGPATH];	char		tempfilepath[MAXPGPATH];	File		file;	/*	 * Identify the tempfile directory for this tablespace.	 *	 * If someone tries to specify pg_global, use pg_default instead.	 */	if (tblspcOid == DEFAULTTABLESPACE_OID ||		tblspcOid == GLOBALTABLESPACE_OID)	{		/* The default tablespace is {datadir}/base */		snprintf(tempdirpath, sizeof(tempdirpath), "base/%s",				 PG_TEMP_FILES_DIR);	}	else	{		/* All other tablespaces are accessed via symlinks */		snprintf(tempdirpath, sizeof(tempdirpath), "pg_tblspc/%u/%s",				 tblspcOid, PG_TEMP_FILES_DIR);	}	/*	 * Generate a tempfile name that should be unique within the current	 * database instance.	 */	snprintf(tempfilepath, sizeof(tempfilepath), "%s/%s%d.%ld",			 tempdirpath, 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 = PathNameOpenFile(tempfilepath,							O_RDWR | O_CREAT | O_TRUNC | PG_BINARY,							0600);	if (file <= 0)	{		/*		 * We might need to create the tablespace's tempfile directory, 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.		 */		mkdir(tempdirpath, S_IRWXU);		file = PathNameOpenFile(tempfilepath,								O_RDWR | O_CREAT | O_TRUNC | PG_BINARY,								0600);		if (file <= 0 && rejectError)			elog(ERROR, "could not create temporary file \"%s\": %m",				 tempfilepath);	}	return file;}/* * close a file when done with it */voidFileClose(File file){	Vfd		   *vfdP;	struct stat filestats;	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, "could not close file \"%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 (log_temp_files >= 0)		{			if (stat(vfdP->fileName, &filestats) == 0)			{				if (filestats.st_size >= log_temp_files)					ereport(LOG,							(errmsg("temporary file: path \"%s\", size %lu",									vfdP->fileName,									(unsigned long) filestats.st_size)));			}			else				elog(LOG, "could not stat file \"%s\": %m", vfdP->fileName);		}		if (unlink(vfdP->fileName))			elog(LOG, "could not unlink file \"%s\": %m", vfdP->fileName);	}	/*	 * Return the Vfd slot to the free list	 */	FreeVfd(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))	{		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:

⌨️ 快捷键说明

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