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

📄 db_am.c

📁 File system using stacked.
💻 C
📖 第 1 页 / 共 3 页
字号:
/*- * See the file LICENSE for redistribution information. * * Copyright (c) 1998-2002 *	Sleepycat Software.  All rights reserved. */#include "db_config.h"#ifndef lintstatic const char revid[] = "$Id: db_am.c,v 1.1.1.1 2004/08/19 23:53:56 gopalan Exp $";#endif /* not lint */#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));static int __db_secondary_close __P((DB *, u_int32_t));#ifdef DEBUGstatic int __db_cprint_item __P((DBC *));#endif/* * __db_cursor -- *	Allocate and return a cursor. * * PUBLIC: int __db_cursor __P((DB *, DB_TXN *, DBC **, u_int32_t)); */int__db_cursor(dbp, txn, dbcp, flags)	DB *dbp;	DB_TXN *txn;	DBC **dbcp;	u_int32_t flags;{	DB_ENV *dbenv;	DBC *dbc;	db_lockmode_t mode;	u_int32_t op;	int ret;	dbenv = dbp->dbenv;	PANIC_CHECK(dbenv);	DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->cursor");	/* Validate arguments. */	if ((ret = __db_cursorchk(dbp, flags)) != 0)		return (ret);	/*	 * Check for consistent transaction usage.  For now, assume that	 * this cursor might be used for read operations only (in which	 * case it may not require a txn).  We'll check more stringently	 * in c_del and c_put.  (Note that this all means that the	 * read-op txn tests have to be a subset of the write-op ones.)	 */	if ((ret = __db_check_txn(dbp, txn, DB_LOCK_INVALIDID, 1)) != 0)		return (ret);	if ((ret = __db_icursor(dbp,	    txn, dbp->type, PGNO_INVALID, 0, DB_LOCK_INVALIDID, dbcp)) != 0)		return (ret);	dbc = *dbcp;	/*	 * If this is CDB, do all the locking in the interface, which is	 * right here.	 */	if (CDB_LOCKING(dbenv)) {		op = LF_ISSET(DB_OPFLAGS_MASK);		mode = (op == DB_WRITELOCK) ? DB_LOCK_WRITE :		    ((op == DB_WRITECURSOR) ? DB_LOCK_IWRITE : DB_LOCK_READ);		if ((ret = dbenv->lock_get(dbenv, dbc->locker, 0,		    &dbc->lock_dbt, mode, &dbc->mylock)) != 0) {			(void)__db_c_close(dbc);			return (ret);		}		if (op == DB_WRITECURSOR)			F_SET(dbc, DBC_WRITECURSOR);		if (op == DB_WRITELOCK)			F_SET(dbc, DBC_WRITER);	}	if (LF_ISSET(DB_DIRTY_READ) ||	    (txn != NULL && F_ISSET(txn, TXN_DIRTY_READ)))		F_SET(dbc, DBC_DIRTY_READ);	return (0);}/* * __db_icursor -- *	Internal version of __db_cursor.  If dbcp is *	non-NULL it is assumed to point to an area to *	initialize as a cursor. * * PUBLIC: int __db_icursor * PUBLIC:     __P((DB *, DB_TXN *, DBTYPE, db_pgno_t, int, u_int32_t, DBC **)); */int__db_icursor(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, *adbc;	DBC_INTERNAL *cp;	DB_ENV *dbenv;	int allocated, ret;	dbenv = dbp->dbenv;	allocated = 0;	/*	 * 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(dbp->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, then there is no need to			 * create new locker ids.  We know that no one else			 * is running concurrently using this DB, so we can			 * take a peek at any cursors on the active queue.			 */			if (!DB_IS_THREADED(dbp) &&			    (adbc = TAILQ_FIRST(&dbp->active_queue)) != NULL)				dbc->lid = adbc->lid;			else {				if ((ret =				    dbenv->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_icursor rather			 * than sdbp->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(dbp->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;		default:			ret = __db_unknown_type(dbp->dbenv,			    "__db_icursor", 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;		txn->cursors++;	}	/*	 * 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;	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;	default:		ret = __db_unknown_type(dbp->dbenv, "__db_icursor", dbp->type);		goto err;	}	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(dbp->dbenv, dbc);	return (ret);}#ifdef DEBUG/* * __db_cprint -- *	Display the cursor active and free queues. * * PUBLIC: int __db_cprint __P((DB *)); */int__db_cprint(dbp)	DB *dbp;{	DBC *dbc;	int ret, t_ret;	ret = 0;	MUTEX_THREAD_LOCK(dbp->dbenv, dbp->mutexp);	fprintf(stderr, "Active queue:\n");	for (dbc = TAILQ_FIRST(&dbp->active_queue);	    dbc != NULL; dbc = TAILQ_NEXT(dbc, links))		if ((t_ret = __db_cprint_item(dbc)) != 0 && ret == 0)			ret = t_ret;	fprintf(stderr, "Free queue:\n");	for (dbc = TAILQ_FIRST(&dbp->free_queue);	    dbc != NULL; dbc = TAILQ_NEXT(dbc, links))		if ((t_ret = __db_cprint_item(dbc)) != 0 && ret == 0)			ret = t_ret;	MUTEX_THREAD_UNLOCK(dbp->dbenv, dbp->mutexp);	return (ret);}staticint __db_cprint_item(dbc)	DBC *dbc;{	static const FN fn[] = {		{ DBC_ACTIVE,		"active" },		{ DBC_COMPENSATE,	"compensate" },		{ DBC_OPD,		"off-page-dup" },		{ DBC_RECOVER,		"recover" },		{ DBC_RMW,		"read-modify-write" },		{ DBC_TRANSIENT,	"transient" },		{ DBC_WRITECURSOR,	"write cursor" },		{ DBC_WRITEDUP,		"internally dup'ed write cursor" },		{ DBC_WRITER,		"short-term write cursor" },		{ 0,			NULL }	};	DB *dbp;	DBC_INTERNAL *cp;	const char *s;	dbp = dbc->dbp;	cp = dbc->internal;	s = __db_dbtype_to_string(dbc->dbtype);	if (strcmp(s, "UNKNOWN TYPE") == 0) {		DB_ASSERT(0);		return (1);	}	fprintf(stderr, "%s/%#0lx: opd: %#0lx\n",	    s, P_TO_ULONG(dbc), P_TO_ULONG(cp->opd));	fprintf(stderr, "\ttxn: %#0lx lid: %lu locker: %lu\n",	    P_TO_ULONG(dbc->txn), (u_long)dbc->lid, (u_long)dbc->locker);	fprintf(stderr, "\troot: %lu page/index: %lu/%lu",	    (u_long)cp->root, (u_long)cp->pgno, (u_long)cp->indx);	__db_prflags(dbc->flags, fn, stderr);	fprintf(stderr, "\n");	switch (dbp->type) {	case DB_BTREE:		__bam_cprint(dbc);		break;	case DB_HASH:		__ham_cprint(dbc);		break;	default:		break;	}	return (0);}#endif /* DEBUG *//* * db_fd -- *	Return a file descriptor for flock'ing. * * PUBLIC: int __db_fd __P((DB *, int *)); */int__db_fd(dbp, fdp)	DB *dbp;	fd_t *fdp;{

⌨️ 快捷键说明

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