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

📄 db.c

📁 这是国外的resip协议栈
💻 C
📖 第 1 页 / 共 3 页
字号:
	    (ret = __dbreg_new_id(dbp, txn)) != 0)		return (ret);	/*	 * Insert ourselves into the DB_ENV's dblist.  We allocate a	 * unique ID to each {fileid, meta page number} pair, and to	 * each temporary file (since they all have a zero fileid).	 * This ID gives us something to use to tell which DB handles	 * go with which databases in all the cursor adjustment	 * routines, where we don't want to do a lot of ugly and	 * expensive memcmps.	 */	MUTEX_THREAD_LOCK(dbenv, dbenv->dblist_mutexp);	for (maxid = 0, ldbp = LIST_FIRST(&dbenv->dblist);	    ldbp != NULL; ldbp = LIST_NEXT(ldbp, dblistlinks)) {		if (fname != NULL &&		    memcmp(ldbp->fileid, dbp->fileid, DB_FILE_ID_LEN) == 0 &&		    ldbp->meta_pgno == dbp->meta_pgno)			break;		if (ldbp->adj_fileid > maxid)			maxid = ldbp->adj_fileid;	}	/*	 * If ldbp is NULL, we didn't find a match, or we weren't	 * really looking because fname is NULL.  Assign the dbp an	 * adj_fileid one higher than the largest we found, and	 * insert it at the head of the master dbp list.	 *	 * If ldbp is not NULL, it is a match for our dbp.  Give dbp	 * the same ID that ldbp has, and add it after ldbp so they're	 * together in the list.	 */	if (ldbp == NULL) {		dbp->adj_fileid = maxid + 1;		LIST_INSERT_HEAD(&dbenv->dblist, dbp, dblistlinks);	} else {		dbp->adj_fileid = ldbp->adj_fileid;		LIST_INSERT_AFTER(ldbp, dbp, dblistlinks);	}	MUTEX_THREAD_UNLOCK(dbenv, dbenv->dblist_mutexp);	return (0);}/* * __db_dbenv_mpool -- *	Set up the underlying environment cache during a db_open. * * PUBLIC: int __db_dbenv_mpool __P((DB *, const char *, u_int32_t)); */int__db_dbenv_mpool(dbp, fname, flags)	DB *dbp;	const char *fname;	u_int32_t flags;{	DB_ENV *dbenv;	DBT pgcookie;	DB_MPOOLFILE *mpf;	DB_PGINFO pginfo;	u_int32_t clear_len;	int ftype, ret;	COMPQUIET(mpf, NULL);	dbenv = dbp->dbenv;	/*	 * If we need to pre- or post-process a file's pages on I/O, set the	 * file type.  If it's a hash file, always call the pgin and pgout	 * routines.  This means that hash files can never be mapped into	 * process memory.  If it's a btree file and requires swapping, we	 * need to page the file in and out.  This has to be right -- we can't	 * mmap files that are being paged in and out.	 */	switch (dbp->type) {	case DB_BTREE:	case DB_RECNO:		ftype = F_ISSET(dbp, DB_AM_SWAP | DB_AM_ENCRYPT | DB_AM_CHKSUM)		    ? DB_FTYPE_SET : DB_FTYPE_NOTSET;		clear_len = CRYPTO_ON(dbenv) ? dbp->pgsize : DB_PAGE_DB_LEN;		break;	case DB_HASH:		ftype = DB_FTYPE_SET;		clear_len = CRYPTO_ON(dbenv) ? dbp->pgsize : DB_PAGE_DB_LEN;		break;	case DB_QUEUE:		ftype = F_ISSET(dbp,		    DB_AM_SWAP | DB_AM_ENCRYPT | DB_AM_CHKSUM) ?		    DB_FTYPE_SET : DB_FTYPE_NOTSET;		clear_len = CRYPTO_ON(dbenv) ? dbp->pgsize : DB_PAGE_QUEUE_LEN;		break;	case DB_UNKNOWN:		/*		 * If we're running in the verifier, our database might		 * be corrupt and we might not know its type--but we may		 * still want to be able to verify and salvage.		 *		 * If we can't identify the type, it's not going to be safe		 * to call __db_pgin--we pretty much have to give up all		 * hope of salvaging cross-endianness.  Proceed anyway;		 * at worst, the database will just appear more corrupt		 * than it actually is, but at best, we may be able		 * to salvage some data even with no metadata page.		 */		if (F_ISSET(dbp, DB_AM_VERIFYING)) {			ftype = DB_FTYPE_NOTSET;			clear_len = DB_PAGE_DB_LEN;			break;		}		/* FALLTHROUGH */	default:		return (__db_unknown_type(dbenv, "DB->open", dbp->type));	}	mpf = dbp->mpf;	(void)__memp_set_clear_len(mpf, clear_len);	(void)__memp_set_fileid(mpf, dbp->fileid);	(void)__memp_set_ftype(mpf, ftype);	(void)__memp_set_lsn_offset(mpf, 0);	pginfo.db_pagesize = dbp->pgsize;	pginfo.flags =	    F_ISSET(dbp, (DB_AM_CHKSUM | DB_AM_ENCRYPT | DB_AM_SWAP));	pginfo.type = dbp->type;	pgcookie.data = &pginfo;	pgcookie.size = sizeof(DB_PGINFO);	(void)__memp_set_pgcookie(mpf, &pgcookie);	if ((ret = __memp_fopen(mpf, NULL, fname,	    LF_ISSET(DB_RDONLY | DB_NOMMAP |	    DB_ODDFILESIZE | DB_TRUNCATE) |	    (F_ISSET(dbenv, DB_ENV_DIRECT_DB) ? DB_DIRECT : 0) |	    (F_ISSET(dbp, DB_AM_NOT_DURABLE) ? DB_TXN_NOT_DURABLE : 0),	    0, dbp->pgsize)) != 0)		return (ret);	return (0);}/* * __db_close -- *	DB->close method. * * PUBLIC: int __db_close __P((DB *, DB_TXN *, u_int32_t)); */int__db_close(dbp, txn, flags)	DB *dbp;	DB_TXN *txn;	u_int32_t flags;{	DB_ENV *dbenv;	int db_ref, deferred_close, ret, t_ret;	dbenv = dbp->dbenv;	deferred_close = ret = 0;	/*	 * Validate arguments, but as a DB handle destructor, we can't fail.	 *	 * Check for consistent transaction usage -- ignore errors.  Only	 * internal callers specify transactions, so it's a serious problem	 * if we get error messages.	 */	if (txn != NULL)		(void)__db_check_txn(dbp, txn, DB_LOCK_INVALIDID, 0);	/* Refresh the structure and close any underlying resources. */	ret = __db_refresh(dbp, txn, flags, &deferred_close);	/*	 * If we've deferred the close because the logging of the close failed,	 * return our failure right away without destroying the handle.	 */	if (deferred_close)		return (ret);	/* !!!	 * This code has an apparent race between the moment we read and	 * decrement dbenv->db_ref and the moment we check whether it's 0.	 * However, if the environment is DBLOCAL, the user shouldn't have a	 * reference to the dbenv handle anyway;  the only way we can get	 * multiple dbps sharing a local dbenv is if we open them internally	 * during something like a subdatabase open.  If any such thing is	 * going on while the user is closing the original dbp with a local	 * dbenv, someone's already badly screwed up, so there's no reason	 * to bother engineering around this possibility.	 */	MUTEX_THREAD_LOCK(dbenv, dbenv->dblist_mutexp);	db_ref = --dbenv->db_ref;	MUTEX_THREAD_UNLOCK(dbenv, dbenv->dblist_mutexp);	if (F_ISSET(dbenv, DB_ENV_DBLOCAL) && db_ref == 0 &&	    (t_ret = __dbenv_close(dbenv, 0)) != 0 && ret == 0)		ret = t_ret;	/* Free the database handle. */	memset(dbp, CLEAR_BYTE, sizeof(*dbp));	__os_free(dbenv, dbp);	return (ret);}/* * __db_refresh -- *	Refresh the DB structure, releasing any allocated resources. * This does most of the work of closing files now because refresh * is what is used during abort processing (since we can't destroy * the actual handle) and during abort processing, we may have a * fully opened handle. * * PUBLIC: int __db_refresh __P((DB *, DB_TXN *, u_int32_t, int *)); */int__db_refresh(dbp, txn, flags, deferred_closep)	DB *dbp;	DB_TXN *txn;	u_int32_t flags;	int *deferred_closep;{	DB *sdbp;	DBC *dbc;	DB_ENV *dbenv;	DB_LOCKREQ lreq;	DB_MPOOL *dbmp;	int resync, ret, t_ret;	ret = 0;	dbenv = dbp->dbenv;	/* If never opened, or not currently open, it's easy. */	if (!F_ISSET(dbp, DB_AM_OPEN_CALLED))		goto never_opened;	/*	 * If we have any secondary indices, disassociate them from us.	 * We don't bother with the mutex here;  it only protects some	 * of the ops that will make us core-dump mid-close anyway, and	 * if you're trying to do something with a secondary *while* you're	 * closing the primary, you deserve what you get.  The disassociation	 * is mostly done just so we can close primaries and secondaries in	 * any order--but within one thread of control.	 */	for (sdbp = LIST_FIRST(&dbp->s_secondaries);	    sdbp != NULL; sdbp = LIST_NEXT(sdbp, s_links)) {		LIST_REMOVE(sdbp, s_links);		if ((t_ret = __db_disassociate(sdbp)) != 0 && ret == 0)			ret = t_ret;	}	/*	 * Sync the underlying access method.  Do before closing the cursors	 * because DB->sync allocates cursors in order to write Recno backing	 * source text files.	 *	 * Sync is slow on some systems, notably Solaris filesystems where the	 * entire buffer cache is searched.  If we're in recovery, don't flush	 * the file, it's not necessary.	 */	if (!LF_ISSET(DB_NOSYNC) &&	    !F_ISSET(dbp, DB_AM_DISCARD | DB_AM_RECOVER) &&	    (t_ret = __db_sync(dbp)) != 0 && ret == 0)		ret = t_ret;	/*	 * Go through the active cursors and call the cursor recycle routine,	 * which resolves pending operations and moves the cursors onto the	 * free list.  Then, walk the free list and call the cursor destroy	 * routine.  Note that any failure on a close is considered "really	 * bad" and we just break out of the loop and force forward.	 */	resync = TAILQ_FIRST(&dbp->active_queue) == NULL ? 0 : 1;	while ((dbc = TAILQ_FIRST(&dbp->active_queue)) != NULL)		if ((t_ret = __db_c_close(dbc)) != 0) {			if (ret == 0)				ret = t_ret;			break;		}	while ((dbc = TAILQ_FIRST(&dbp->free_queue)) != NULL)		if ((t_ret = __db_c_destroy(dbc)) != 0) {			if (ret == 0)				ret = t_ret;			break;		}	/*	 * Close any outstanding join cursors.  Join cursors destroy themselves	 * on close and have no separate destroy routine.  We don't have to set	 * the resync flag here, because join cursors aren't write cursors.	 */	while ((dbc = TAILQ_FIRST(&dbp->join_queue)) != NULL)		if ((t_ret = __db_join_close(dbc)) != 0) {			if (ret == 0)				ret = t_ret;			break;		}	/*	 * Sync the memory pool, even though we've already called DB->sync,	 * because closing cursors can dirty pages by deleting items they	 * referenced.	 *	 * Sync is slow on some systems, notably Solaris filesystems where the	 * entire buffer cache is searched.  If we're in recovery, don't flush	 * the file, it's not necessary.	 */	if (resync && !LF_ISSET(DB_NOSYNC) &&	    !F_ISSET(dbp, DB_AM_DISCARD | DB_AM_RECOVER) &&	    (t_ret = __memp_fsync(dbp->mpf)) != 0 && ret == 0)		ret = t_ret;	/*	 * At this point, we haven't done anything to render the DB	 * handle unusable, at least by a transaction abort.  Take the	 * opportunity now to log the file close.  If this log fails	 * and we're in a transaction, we have to bail out of the attempted	 * close; we'll need a dbp in order to successfully abort the	 * transaction, and we can't conjure a new one up because we haven't	 * gotten out the dbreg_register record that represents the close.	 * In this case, we put off actually closing the dbp until we've	 * performed the abort.	 */	if (LOGGING_ON(dbp->dbenv)) {		/*		 * Discard the log file id, if any.  We want to log the close		 * if and only if this is not a recovery dbp.		 */		if (F_ISSET(dbp, DB_AM_RECOVER))			t_ret = __dbreg_revoke_id(dbp, 0, DB_LOGFILEID_INVALID);		else {			if ((t_ret = __dbreg_close_id(dbp,			    txn, DBREG_CLOSE)) != 0 && txn != NULL) {				/*				 * We're in a txn and the attempt to log the				 * close failed;  let the txn subsystem know				 * that we need to destroy this dbp once we're				 * done with the abort, then bail from the				 * close.				 *				 * Note that if the attempt to put off the				 * close -also- fails--which it won't unless				 * we're out of heap memory--we're really				 * screwed.  Panic.				 */				if ((ret =				    __txn_closeevent(dbenv, txn, dbp)) != 0)					return (__db_panic(dbenv, ret));				if (deferred_closep != NULL)					*deferred_closep = 1;				return (t_ret);			}		}		if (ret == 0)			ret = t_ret;		/* Discard the log FNAME. */		if ((t_ret = __dbreg_teardown(dbp)) != 0 && ret == 0)			ret = t_ret;	}	/* Close any handle we've been holding since the open.  */	if (dbp->saved_open_fhp != NULL &&	    (t_ret = __os_closehandle(dbenv, dbp->saved_open_fhp)) != 0 &&	    ret == 0)		ret = t_ret;never_opened:	/*	 * Remove this DB handle from the DB_ENV's dblist, if it's been added.	 *	 * Close our reference to the underlying cache while locked, we don't	 * want to race with a thread searching for our underlying cache link	 * while opening a DB handle.	 */	MUTEX_THREAD_LOCK(dbenv, dbenv->dblist_mutexp);	if (dbp->dblistlinks.le_prev != NULL) {		LIST_REMOVE(dbp, dblistlinks);		dbp->dblistlinks.le_prev = NULL;	}	/* Close the memory pool file handle. */	if (dbp->mpf != NULL) {		if ((t_ret = __memp_fclose(dbp->mpf,		    F_ISSET(dbp, DB_AM_DISCARD) ? DB_MPOOL_DISCARD : 0)) != 0 &&		    ret == 0)			ret = t_ret;		dbp->mpf = NULL;	}	MUTEX_THREAD_UNLOCK(dbenv, dbenv->dblist_mutexp);	/*	 * Call the access specific close function.	 *	 * We do this here rather than in __db_close as we need to do this when	 * aborting an open so that file descriptors are closed and abort of	 * renames can succeed on platforms that lock open files (such as	 * Windows).  In particular, we need to ensure that all the extents	 * associated with a queue are closed so that queue renames can be	 * aborted.	 *	 * It is also important that we do this before releasing the handle	 * lock, because dbremove and dbrename assume that once they have the	 * handle lock, it is safe to modify the underlying file(s).	 *	 * !!!	 * Because of where these functions are called in the DB handle close	 * process, these routines can't do anything that would dirty pages or	 * otherwise affect closing down the database.  Specifically, we can't	 * abort and recover any of the information they control.	 */	if ((t_ret = __bam_db_close(dbp)) != 0 && ret == 0)		ret = t_ret;	if ((t_ret = __ham_db_close(dbp)) != 0 && ret == 0)		ret = t_ret;	if ((t_ret = __qam_db_close(dbp, dbp->flags)) != 0 && ret == 0)		ret = t_ret;	/*	 * !!!	 * At this point, the access-method specific information has been	 * freed.  From now on, we can use the dbp, but not touch any	 * access-method specific data.	 */	if (dbp->lid != DB_LOCK_INVALIDID) {		/* We may have pending trade operations on this dbp. */		if (txn != NULL)			__txn_remlock(dbenv, txn, &dbp->handle_lock, dbp->lid);		/* We may be holding the handle lock; release it. */		lreq.op = DB_LOCK_PUT_ALL;		lreq.obj = NULL;		if ((t_ret = __lock_vec(dbenv,		    dbp->lid, 0, &lreq, 1, NULL)) != 0 && ret == 0)			ret = t_ret;		if ((t_ret = __lock_id_free(dbenv, dbp->lid)) != 0 && ret == 0)			ret = t_ret;		dbp->lid = DB_LOCK_INVALIDID;		LOCK_INIT(dbp->handle_lock);	}	/* Discard the locker ID allocated as the fileid. */	if (F_ISSET(dbp, DB_AM_INMEM) && LOCKING_ON(dbenv) &&	    (t_ret = __lock_id_free(dbenv, *(u_int32_t *)dbp->fileid)) != 0 &&	    ret == 0)		ret = t_ret;	dbp->type = DB_UNKNOWN;

⌨️ 快捷键说明

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