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

📄 db_am.c

📁 这是国外的resip协议栈
💻 C
📖 第 1 页 / 共 2 页
字号:
/*- * See the file LICENSE for redistribution information. * * Copyright (c) 1998-2004 *	Sleepycat Software.  All rights reserved. * * $Id: db_am.c,v 11.120 2004/10/07 17:33:32 sue Exp $ */#include "db_config.h"#ifndef NO_SYSTEM_INCLUDES#include <sys/types.h>#include <string.h>#endif#include "db_int.h"#include "dbinc/db_page.h"#include "dbinc/db_shash.h"#include "dbinc/btree.h"#include "dbinc/hash.h"#include "dbinc/lock.h"#include "dbinc/log.h"#include "dbinc/mp.h"#include "dbinc/qam.h"static int __db_append_primary __P((DBC *, DBT *, DBT *));static int __db_secondary_get __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t));/* * __db_cursor_int -- *	Internal routine to create a cursor. * * PUBLIC: int __db_cursor_int * PUBLIC:     __P((DB *, DB_TXN *, DBTYPE, db_pgno_t, int, u_int32_t, DBC **)); */int__db_cursor_int(dbp, txn, dbtype, root, is_opd, lockerid, dbcp)	DB *dbp;	DB_TXN *txn;	DBTYPE dbtype;	db_pgno_t root;	int is_opd;	u_int32_t lockerid;	DBC **dbcp;{	DBC *dbc;	DBC_INTERNAL *cp;	DB_ENV *dbenv;	int allocated, ret;	dbenv = dbp->dbenv;	allocated = 0;	/*	 * If dbcp is non-NULL it is assumed to point to an area to initialize	 * as a cursor.	 *	 * Take one from the free list if it's available.  Take only the	 * right type.  With off page dups we may have different kinds	 * of cursors on the queue for a single database.	 */	MUTEX_THREAD_LOCK(dbenv, dbp->mutexp);	for (dbc = TAILQ_FIRST(&dbp->free_queue);	    dbc != NULL; dbc = TAILQ_NEXT(dbc, links))		if (dbtype == dbc->dbtype) {			TAILQ_REMOVE(&dbp->free_queue, dbc, links);			F_CLR(dbc, ~DBC_OWN_LID);			break;		}	MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp);	if (dbc == NULL) {		if ((ret = __os_calloc(dbenv, 1, sizeof(DBC), &dbc)) != 0)			return (ret);		allocated = 1;		dbc->flags = 0;		dbc->dbp = dbp;		/* Set up locking information. */		if (LOCKING_ON(dbenv)) {			/*			 * If we are not threaded, we share a locker ID among			 * all cursors opened in the environment handle,			 * allocating one if this is the first cursor.			 *			 * This relies on the fact that non-threaded DB handles			 * always have non-threaded environment handles, since			 * we set DB_THREAD on DB handles created with threaded			 * environment handles.			 */			if (!DB_IS_THREADED(dbp)) {				if (dbp->dbenv->env_lid == DB_LOCK_INVALIDID &&				    (ret =				    __lock_id(dbenv,&dbp->dbenv->env_lid)) != 0)					goto err;				dbc->lid = dbp->dbenv->env_lid;			} else {				if ((ret = __lock_id(dbenv, &dbc->lid)) != 0)					goto err;				F_SET(dbc, DBC_OWN_LID);			}			/*			 * In CDB, secondary indices should share a lock file			 * ID with the primary;  otherwise we're susceptible			 * to deadlocks.  We also use __db_cursor_int rather			 * than __db_cursor to create secondary update cursors			 * in c_put and c_del; these won't acquire a new lock.			 *			 * !!!			 * Since this is in the one-time cursor allocation			 * code, we need to be sure to destroy, not just			 * close, all cursors in the secondary when we			 * associate.			 */			if (CDB_LOCKING(dbenv) &&			    F_ISSET(dbp, DB_AM_SECONDARY))				memcpy(dbc->lock.fileid,				    dbp->s_primary->fileid, DB_FILE_ID_LEN);			else				memcpy(dbc->lock.fileid,				    dbp->fileid, DB_FILE_ID_LEN);			if (CDB_LOCKING(dbenv)) {				if (F_ISSET(dbenv, DB_ENV_CDB_ALLDB)) {					/*					 * If we are doing a single lock per					 * environment, set up the global					 * lock object just like we do to					 * single thread creates.					 */					DB_ASSERT(sizeof(db_pgno_t) ==					    sizeof(u_int32_t));					dbc->lock_dbt.size = sizeof(u_int32_t);					dbc->lock_dbt.data = &dbc->lock.pgno;					dbc->lock.pgno = 0;				} else {					dbc->lock_dbt.size = DB_FILE_ID_LEN;					dbc->lock_dbt.data = dbc->lock.fileid;				}			} else {				dbc->lock.type = DB_PAGE_LOCK;				dbc->lock_dbt.size = sizeof(dbc->lock);				dbc->lock_dbt.data = &dbc->lock;			}		}		/* Init the DBC internal structure. */		switch (dbtype) {		case DB_BTREE:		case DB_RECNO:			if ((ret = __bam_c_init(dbc, dbtype)) != 0)				goto err;			break;		case DB_HASH:			if ((ret = __ham_c_init(dbc)) != 0)				goto err;			break;		case DB_QUEUE:			if ((ret = __qam_c_init(dbc)) != 0)				goto err;			break;		case DB_UNKNOWN:		default:			ret = __db_unknown_type(dbenv, "DB->cursor", dbtype);			goto err;		}		cp = dbc->internal;	}	/* Refresh the DBC structure. */	dbc->dbtype = dbtype;	RESET_RET_MEM(dbc);	if ((dbc->txn = txn) == NULL) {		/*		 * There are certain cases in which we want to create a		 * new cursor with a particular locker ID that is known		 * to be the same as (and thus not conflict with) an		 * open cursor.		 *		 * The most obvious case is cursor duplication;  when we		 * call DBC->c_dup or __db_c_idup, we want to use the original		 * cursor's locker ID.		 *		 * Another case is when updating secondary indices.  Standard		 * CDB locking would mean that we might block ourself:  we need		 * to open an update cursor in the secondary while an update		 * cursor in the primary is open, and when the secondary and		 * primary are subdatabases or we're using env-wide locking,		 * this is disastrous.		 *		 * In these cases, our caller will pass a nonzero locker ID		 * into this function.  Use this locker ID instead of dbc->lid		 * as the locker ID for our new cursor.		 */		if (lockerid != DB_LOCK_INVALIDID)			dbc->locker = lockerid;		else			dbc->locker = dbc->lid;	} else		dbc->locker = txn->txnid;	/*	 * These fields change when we are used as a secondary index, so	 * if the DB is a secondary, make sure they're set properly just	 * in case we opened some cursors before we were associated.	 *	 * __db_c_get is used by all access methods, so this should be safe.	 */	if (F_ISSET(dbp, DB_AM_SECONDARY))		dbc->c_get = __db_c_secondary_get_pp;	if (is_opd)		F_SET(dbc, DBC_OPD);	if (F_ISSET(dbp, DB_AM_RECOVER))		F_SET(dbc, DBC_RECOVER);	if (F_ISSET(dbp, DB_AM_COMPENSATE))		F_SET(dbc, DBC_COMPENSATE);	/* Refresh the DBC internal structure. */	cp = dbc->internal;	cp->opd = NULL;	cp->indx = 0;	cp->page = NULL;	cp->pgno = PGNO_INVALID;	cp->root = root;	switch (dbtype) {	case DB_BTREE:	case DB_RECNO:		if ((ret = __bam_c_refresh(dbc)) != 0)			goto err;		break;	case DB_HASH:	case DB_QUEUE:		break;	case DB_UNKNOWN:	default:		ret = __db_unknown_type(dbenv, "DB->cursor", dbp->type);		goto err;	}	/*	 * The transaction keeps track of how many cursors were opened within	 * it to catch application errors where the cursor isn't closed when	 * the transaction is resolved.	 */	if (txn != NULL)		++txn->cursors;	MUTEX_THREAD_LOCK(dbenv, dbp->mutexp);	TAILQ_INSERT_TAIL(&dbp->active_queue, dbc, links);	F_SET(dbc, DBC_ACTIVE);	MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp);	*dbcp = dbc;	return (0);err:	if (allocated)		__os_free(dbenv, dbc);	return (ret);}/* * __db_put -- *	Store a key/data pair. * * PUBLIC: int __db_put __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t)); */int__db_put(dbp, txn, key, data, flags)	DB *dbp;	DB_TXN *txn;	DBT *key, *data;	u_int32_t flags;{	DBC *dbc;	DBT tdata;	DB_ENV *dbenv;	int ret, t_ret;	dbenv = dbp->dbenv;	if ((ret = __db_cursor(dbp, txn, &dbc, DB_WRITELOCK)) != 0)		return (ret);	DEBUG_LWRITE(dbc, txn, "DB->put", key, data, flags);	SET_RET_MEM(dbc, dbp);	/*	 * See the comment in __db_get().	 *	 * Note that the c_get in the DB_NOOVERWRITE case is safe to	 * do with this flag set;  if it errors in any way other than	 * DB_NOTFOUND, we're going to close the cursor without doing	 * anything else, and if it returns DB_NOTFOUND then it's safe	 * to do a c_put(DB_KEYLAST) even if an access method moved the	 * cursor, since that's not position-dependent.	 */	F_SET(dbc, DBC_TRANSIENT);	switch (flags) {	case DB_APPEND:		/*		 * If there is an append callback, the value stored in		 * data->data may be replaced and then freed.  To avoid		 * passing a freed pointer back to the user, just operate		 * on a copy of the data DBT.		 */		tdata = *data;		/*		 * Append isn't a normal put operation;  call the appropriate		 * access method's append function.		 */		switch (dbp->type) {		case DB_QUEUE:			if ((ret = __qam_append(dbc, key, &tdata)) != 0)				goto err;			break;		case DB_RECNO:			if ((ret = __ram_append(dbc, key, &tdata)) != 0)				goto err;			break;		case DB_BTREE:		case DB_HASH:		case DB_UNKNOWN:		default:			/* The interface should prevent this. */			DB_ASSERT(			    dbp->type == DB_QUEUE || dbp->type == DB_RECNO);			ret = __db_ferr(dbenv, "DB->put", 0);			goto err;		}		/*		 * Secondary indices:  since we've returned zero from		 * an append function, we've just put a record, and done		 * so outside __db_c_put.  We know we're not a secondary--		 * the interface prevents puts on them--but we may be a		 * primary.  If so, update our secondary indices		 * appropriately.		 */		DB_ASSERT(!F_ISSET(dbp, DB_AM_SECONDARY));		if (LIST_FIRST(&dbp->s_secondaries) != NULL)			ret = __db_append_primary(dbc, key, &tdata);		/*		 * The append callback, if one exists, may have allocated		 * a new tdata.data buffer.  If so, free it.		 */		FREE_IF_NEEDED(dbp, &tdata);		/* No need for a cursor put;  we're done. */		goto done;	case DB_NOOVERWRITE:		flags = 0;		/*		 * Set DB_DBT_USERMEM, this might be a threaded application and		 * the flags checking will catch us.  We don't want the actual		 * data, so request a partial of length 0.		 */		memset(&tdata, 0, sizeof(tdata));		F_SET(&tdata, DB_DBT_USERMEM | DB_DBT_PARTIAL);		/*		 * If we're doing page-level locking, set the read-modify-write		 * flag, we're going to overwrite immediately.		 */		if ((ret = __db_c_get(dbc, key, &tdata,		    DB_SET | (STD_LOCKING(dbc) ? DB_RMW : 0))) == 0)			ret = DB_KEYEXIST;		else if (ret == DB_NOTFOUND || ret == DB_KEYEMPTY)			ret = 0;		break;	default:		/* Fall through to normal cursor put. */		break;	}	if (ret == 0)		ret = __db_c_put(dbc,		    key, data, flags == 0 ? DB_KEYLAST : flags);err:done:	/* Close the cursor. */	if ((t_ret = __db_c_close(dbc)) != 0 && ret == 0)		ret = t_ret;	return (ret);}/* * __db_del -- *	Delete the items referenced by a key. * * PUBLIC: int __db_del __P((DB *, DB_TXN *, DBT *, u_int32_t)); */int__db_del(dbp, txn, key, flags)	DB *dbp;	DB_TXN *txn;	DBT *key;	u_int32_t flags;{	DBC *dbc;	DBT data, lkey;	u_int32_t f_init, f_next;	int ret, t_ret;	/* Allocate a cursor. */	if ((ret = __db_cursor(dbp, txn, &dbc, DB_WRITELOCK)) != 0)		goto err;	DEBUG_LWRITE(dbc, txn, "DB->del", key, NULL, flags);	COMPQUIET(flags, 0);	/*	 * Walk a cursor through the key/data pairs, deleting as we go.  Set	 * the DB_DBT_USERMEM flag, as this might be a threaded application	 * and the flags checking will catch us.  We don't actually want the	 * keys or data, so request a partial of length 0.	 */	memset(&lkey, 0, sizeof(lkey));	F_SET(&lkey, DB_DBT_USERMEM | DB_DBT_PARTIAL);

⌨️ 快捷键说明

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