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

📄 fop_util.c

📁 这是国外的resip协议栈
💻 C
📖 第 1 页 / 共 3 页
字号:
/*- * See the file LICENSE for redistribution information. * * Copyright (c) 2001-2004 *	Sleepycat Software.  All rights reserved. * * $Id: fop_util.c,v 1.104 2004/09/24 00:43:18 bostic Exp $ */#include "db_config.h"#ifndef NO_SYSTEM_INCLUDES#include <sys/types.h>#include <stdlib.h>#include <string.h>#endif#include "db_int.h"#include "dbinc/db_page.h"#include "dbinc/db_shash.h"#include "dbinc/db_am.h"#include "dbinc/fop.h"#include "dbinc/lock.h"#include "dbinc/mp.h"#include "dbinc/log.h"#include "dbinc/txn.h"static int __fop_set_pgsize __P((DB *, DB_FH *, const char *));/* * Acquire the environment meta-data lock.  The parameters are the * environment (ENV), the locker id to use in acquiring the lock (ID) * and a pointer to a DB_LOCK. * * !!! * Turn off locking for Critical Path.  The application must do its own * synchronization of open/create.  Two threads creating and opening a * file at the same time may have unpredictable results. */#ifdef CRITICALPATH_10266#define	GET_ENVLOCK(ENV, ID, L) (0)#else#define	GET_ENVLOCK(ENV, ID, L) do {					\	DBT __dbt;							\	u_int32_t __lockval;						\									\	if (LOCKING_ON((ENV))) {					\		__lockval = 1;						\		__dbt.data = &__lockval;				\		__dbt.size = sizeof(__lockval);				\		if ((ret = __lock_get((ENV), (ID),			\		    0, &__dbt, DB_LOCK_WRITE, (L))) != 0)		\			goto err;					\	}								\} while (0)#endif/* * If we open a file handle and our caller is doing fcntl(2) locking, * we can't close the handle because that would discard the caller's * lock. Save it until we close or refresh the DB handle. */#define	CLOSE_HANDLE(D, F) {						\	if ((F) != NULL) {						\		if (LF_ISSET(DB_FCNTL_LOCKING))				\			(D)->saved_open_fhp = (F);			\		else if ((t_ret =					\		    __os_closehandle((D)->dbenv, (F))) != 0) {		\			if (ret == 0)					\				ret = t_ret;				\			goto err;					\		}							\		(F) = NULL;						\	}								\}/* * __fop_lock_handle -- * * Get the handle lock for a database.  If the envlock is specified, do this * as a lock_vec call that releases the environment lock before acquiring the * handle lock. * * PUBLIC: int __fop_lock_handle __P((DB_ENV *, * PUBLIC:     DB *, u_int32_t, db_lockmode_t, DB_LOCK *, u_int32_t)); * */int__fop_lock_handle(dbenv, dbp, locker, mode, elockp, flags)	DB_ENV *dbenv;	DB *dbp;	u_int32_t locker;	db_lockmode_t mode;	DB_LOCK *elockp;	u_int32_t flags;{	DBT fileobj;	DB_LOCKREQ reqs[2], *ereq;	DB_LOCK_ILOCK lock_desc;	int ret;	if (!LOCKING_ON(dbenv) ||	    F_ISSET(dbp, DB_AM_COMPENSATE | DB_AM_RECOVER))		return (0);	/*	 * If we are in recovery, the only locking we should be	 * doing is on the global environment.	 */	if (IS_RECOVERING(dbenv))		return (elockp == NULL ? 0 : __ENV_LPUT(dbenv, *elockp, 0));	memcpy(lock_desc.fileid, dbp->fileid, DB_FILE_ID_LEN);	lock_desc.pgno = dbp->meta_pgno;	lock_desc.type = DB_HANDLE_LOCK;	memset(&fileobj, 0, sizeof(fileobj));	fileobj.data = &lock_desc;	fileobj.size = sizeof(lock_desc);	DB_TEST_SUBLOCKS(dbenv, flags);	if (elockp == NULL)		ret = __lock_get(dbenv, locker,		    flags, &fileobj, mode, &dbp->handle_lock);	else {		reqs[0].op = DB_LOCK_PUT;		reqs[0].lock = *elockp;		reqs[1].op = DB_LOCK_GET;		reqs[1].mode = mode;		reqs[1].obj = &fileobj;		reqs[1].timeout = 0;		if ((ret = __lock_vec(dbenv,		    locker, flags, reqs, 2, &ereq)) == 0) {			dbp->handle_lock = reqs[1].lock;			LOCK_INIT(*elockp);		} else if (ereq != reqs)			LOCK_INIT(*elockp);	}	dbp->cur_lid = locker;	return (ret);}/* * __fop_file_setup -- * * Perform all the needed checking and locking to open up or create a * file. * * There's a reason we don't push this code down into the buffer cache. * The problem is that there's no information external to the file that * we can use as a unique ID.  UNIX has dev/inode pairs, but they are * not necessarily unique after reboot, if the file was mounted via NFS. * Windows has similar problems, as the FAT filesystem doesn't maintain * dev/inode numbers across reboot.  So, we must get something from the * file we can use to ensure that, even after a reboot, the file we're * joining in the cache is the right file for us to join.  The solution * we use is to maintain a file ID that's stored in the database, and * that's why we have to open and read the file before calling into the * buffer cache or obtaining a lock (we use this unique fileid to lock * as well as to identify like files in the cache). * * There are a couple of idiosyncrasies that this code must support, in * particular, DB_TRUNCATE and DB_FCNTL_LOCKING.  First, we disallow * DB_TRUNCATE in the presence of transactions, since opening a file with * O_TRUNC will result in data being lost in an unrecoverable fashion. * We also disallow DB_TRUNCATE if locking is enabled, because even in * the presence of locking, we cannot avoid race conditions, so allowing * DB_TRUNCATE with locking would be misleading.  See SR [#7345] for more * details. * * However, if you are running with neither locking nor transactions, then * you can specify DB_TRUNCATE, and if you do so, we will truncate the file * regardless of its contents. * * FCNTL locking introduces another set of complications.  First, the only * reason we support the DB_FCNTL_LOCKING flag is for historic compatibility * with programs like Sendmail and Postfix.  In these cases, the caller may * already have a lock on the file; we need to make sure that any file handles * we open remain open, because if we were to close them, the lock held by the * caller would go away.  Furthermore, Sendmail and/or Postfix need the ability * to create databases in empty files.  So, when you're doing FCNTL locking, * it's reasonable that you are trying to create a database into a 0-length * file and we allow it, while under normal conditions, we do not create * databases if the files already exist and are not Berkeley DB files. * * PUBLIC: int __fop_file_setup __P((DB *, * PUBLIC:     DB_TXN *, const char *, int, u_int32_t, u_int32_t *)); */int__fop_file_setup(dbp, txn, name, mode, flags, retidp)	DB *dbp;	DB_TXN *txn;	const char *name;	int mode;	u_int32_t flags, *retidp;{	DB_ENV *dbenv;	DB_FH *fhp;	DB_LOCK elock;	DB_TXN *stxn;	size_t len;	u_int32_t dflags, locker, oflags;	u_int8_t mbuf[DBMETASIZE];	int created_locker, ret, retries, t_ret, tmp_created, truncating;	char *real_name, *real_tmpname, *tmpname;	DB_ASSERT(name != NULL);	*retidp = TXN_INVALID;	dbenv = dbp->dbenv;	fhp = NULL;	LOCK_INIT(elock);	stxn = NULL;	created_locker = tmp_created = truncating = 0;	real_name = real_tmpname = tmpname = NULL;	dflags = F_ISSET(dbp, DB_AM_NOT_DURABLE) ? DB_LOG_NOT_DURABLE : 0;	/*	 * Get a lockerid for this handle.  There are paths through queue	 * rename and remove where this dbp already has a locker, so make	 * sure we don't clobber it and conflict.	 */	if (LOCKING_ON(dbenv) &&	    !F_ISSET(dbp, DB_AM_COMPENSATE) &&	    !F_ISSET(dbp, DB_AM_RECOVER) &&	    dbp->lid == DB_LOCK_INVALIDID) {		if ((ret = __lock_id(dbenv, &dbp->lid)) != 0)			goto err;		created_locker = 1;	}	LOCK_INIT(dbp->handle_lock);	locker = txn == NULL ? dbp->lid : txn->txnid;	/* Get the real backing file name. */	if ((ret = __db_appname(dbenv,	    DB_APP_DATA, name, 0, NULL, &real_name)) != 0)		goto err;	/* Fill in the default file mode. */	if (mode == 0)		mode = __db_omode("rwrw--");	oflags = 0;	if (LF_ISSET(DB_RDONLY))		oflags |= DB_OSO_RDONLY;	if (LF_ISSET(DB_TRUNCATE))		oflags |= DB_OSO_TRUNC;	retries = 0;retry:	/*	 * If we cannot create the file, only retry a few times.  We	 * think we might be in a race with another create, but it could	 * be that the backup filename exists (that is, is left over from	 * a previous crash).	 */	if (++retries > DB_RETRY) {		__db_err(dbenv, "__fop_file_setup:  Retry limit (%d) exceeded",		    DB_RETRY);		goto err;	}	if (!F_ISSET(dbp, DB_AM_COMPENSATE) && !F_ISSET(dbp, DB_AM_RECOVER))		GET_ENVLOCK(dbenv, locker, &elock);	if ((ret = __os_exists(real_name, NULL)) == 0) {		/*		 * If the file exists, there are 5 possible cases:		 * 1. DB_EXCL was specified so this is an error, unless		 *	this is a file left around after a rename and we		 *	are in the same transaction.  This gets decomposed		 *	into several subcases, because we check for various		 *	errors before we know we're in rename.		 * 2. We are truncating, and it doesn't matter what kind		 *	of file it is, we should open/create it.		 * 3. It is 0-length, we are not doing transactions (i.e.,		 *      we are sendmail), we should open/create into it.		 * 4. Is it a Berkeley DB file and we should simply open it.		 * 5. It is not a BDB file and we should return an error.		 */		/* We have to open the file. */reopen:		if ((ret = __os_open(dbenv, real_name, oflags, 0, &fhp)) != 0)			goto err;		/* Case 2: DB_TRUNCATE: we must do the creation in place. */		if (LF_ISSET(DB_TRUNCATE)) {			if (LF_ISSET(DB_EXCL)) {				/* Case 1a: DB_EXCL and DB_TRUNCATE. */				ret = EEXIST;				goto err;			}			tmpname = (char *)name;			goto creat2;		}		/* Cases 1,3-5: we need to read the meta-data page. */		ret = __fop_read_meta(dbenv, real_name, mbuf, sizeof(mbuf), fhp,		    LF_ISSET(DB_FCNTL_LOCKING) && txn == NULL ? 1 : 0, &len);		/* Case 3: 0-length, no txns. */		if (ret != 0 && len == 0 && txn == NULL) {			if (LF_ISSET(DB_EXCL)) {				/* Case 1b: DB_EXCL and 0-lenth file exists. */				ret = EEXIST;				goto err;			}			tmpname = (char *)name;			goto creat2;		}		/* Case 5: Invalid file. */		if (ret != 0)			goto err;		/* Case 4: This is a valid file. */		if ((ret = __db_meta_setup(dbenv,		    dbp, real_name, (DBMETA *)mbuf, flags, 1)) != 0)			goto err;		/* Now, get our handle lock. */		if ((ret = __fop_lock_handle(dbenv,		    dbp, locker, DB_LOCK_READ, NULL, DB_LOCK_NOWAIT)) == 0) {			if ((ret = __ENV_LPUT(dbenv, elock, 0)) != 0)				goto err;		} else if (ret != DB_LOCK_NOTGRANTED ||		    (txn != NULL && F_ISSET(txn, TXN_NOWAIT)))			goto err;		else {			/*			 * We were unable to acquire the handle lock without			 * blocking.  The fact that we are blocking might mean			 * that someone else is trying to delete the file.			 * Since some platforms cannot delete files while they			 * are open (Windows), we are going to have to close			 * the file.  This would be a problem if we were doing			 * FCNTL locking, because our closing the handle would			 * release the FCNTL locks.  Fortunately, if we are			 * doing FCNTL locking, then we should never fail to			 * acquire our handle lock, so we should never get here.			 * We assert it here to make sure we aren't destroying			 * any application level FCNTL semantics.			 */			DB_ASSERT(!LF_ISSET(DB_FCNTL_LOCKING));			if ((ret = __os_closehandle(dbenv, fhp)) != 0)				goto err;			fhp = NULL;			ret = __fop_lock_handle(dbenv,			    dbp, locker, DB_LOCK_READ, &elock, 0);			if (ret == DB_LOCK_NOTEXIST)				goto retry;			if (ret != 0)				goto err;			/*			 * XXX			 * I need to convince myself that I don't need to			 * re-read the metadata page here.  If you do need			 * to re-read it you'd better decrypt it too...			 */			if ((ret =			    __os_open(dbenv, real_name, 0, 0, &fhp)) != 0)				goto err;		}		/* If we got here, then we now have the handle lock. */		/*		 * Check for a file in the midst of a rename.  If we find that		 * the file is in the midst of a rename, it must be the case		 * that it is in our current transaction (else we would still		 * be blocking), so we can continue along and create a new file		 * with the same name.  In that case, we have to close the file		 * handle because we reuse it below.		 */		if (F_ISSET(dbp, DB_AM_IN_RENAME)) {			if (LF_ISSET(DB_CREATE)) {				if ((ret = __os_closehandle(dbenv, fhp)) != 0)					goto err;				goto create;			} else {				ret = ENOENT;				goto err;			}		}		/*		 * Now, case 1: check for DB_EXCL, because the file that exists		 * is not in the middle of a rename, so we have an error.  This		 * is a weird case, but we need to make sure that we don't		 * continue to hold the handle lock, since technically, we		 * should not have been allowed to open it.		 */		if (LF_ISSET(DB_EXCL)) {			ret = __ENV_LPUT(dbenv, dbp->handle_lock, 0);			LOCK_INIT(dbp->handle_lock);			if (ret == 0)

⌨️ 快捷键说明

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