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

📄 bt_cursor.c

📁 这是国外的resip协议栈
💻 C
📖 第 1 页 / 共 5 页
字号:
done:	/*	 * If we inserted a key into the first or last slot of the tree,	 * remember where it was so we can do it more quickly next time.	 * If the tree has record numbers, we need a complete stack so	 * that we can adjust the record counts, so skipping the tree search	 * isn't possible.  For subdatabases we need to be careful that the	 * page does not move from one db to another, so we track its LSN.	 *	 * If there are duplicates and we are inserting into the last slot,	 * the cursor will point _to_ the last item, not after it, which	 * is why we subtract P_INDX below.	 */	t = dbp->bt_internal;	if (ret == 0 && TYPE(cp->page) == P_LBTREE &&	    (flags == DB_KEYFIRST || flags == DB_KEYLAST) &&	    !F_ISSET(cp, C_RECNUM) &&	    (!F_ISSET(dbp, DB_AM_SUBDB) ||	    (LOGGING_ON(dbp->dbenv) && !F_ISSET(dbp, DB_AM_NOT_DURABLE))) &&	    ((NEXT_PGNO(cp->page) == PGNO_INVALID &&	    cp->indx >= NUM_ENT(cp->page) - P_INDX) ||	    (PREV_PGNO(cp->page) == PGNO_INVALID && cp->indx == 0))) {		t->bt_lpgno = cp->pgno;		if (F_ISSET(dbp, DB_AM_SUBDB))			t->bt_llsn = LSN(cp->page);	} else		t->bt_lpgno = PGNO_INVALID;	/*	 * Discard any pages pinned in the tree and their locks, except for	 * the leaf page.  Note, the leaf page participated in any stack we	 * acquired, and so we have to adjust the stack as necessary.  If	 * there was only a single page on the stack, we don't have to free	 * further stack pages.	 */	if (stack && BT_STK_POP(cp) != NULL)		(void)__bam_stkrel(dbc, 0);	/*	 * Regardless of whether we were successful or not, clear the delete	 * flag.  If we're successful, we either moved the cursor or the item	 * is no longer deleted.  If we're not successful, then we're just a	 * copy, no need to have the flag set.	 *	 * We may have instantiated off-page duplicate cursors during the put,	 * so clear the deleted bit from the off-page duplicate cursor as well.	 */	F_CLR(cp, C_DELETED);	if (cp->opd != NULL) {		cp = (BTREE_CURSOR *)cp->opd->internal;		F_CLR(cp, C_DELETED);	}	return (ret);}/* * __bam_c_rget -- *	Return the record number for a cursor. * * PUBLIC: int __bam_c_rget __P((DBC *, DBT *)); */int__bam_c_rget(dbc, data)	DBC *dbc;	DBT *data;{	BTREE_CURSOR *cp;	DB *dbp;	DBT dbt;	DB_MPOOLFILE *mpf;	db_recno_t recno;	int exact, ret, t_ret;	dbp = dbc->dbp;	mpf = dbp->mpf;	cp = (BTREE_CURSOR *)dbc->internal;	/*	 * Get the page with the current item on it.	 * Get a copy of the key.	 * Release the page, making sure we don't release it twice.	 */	if ((ret = __memp_fget(mpf, &cp->pgno, 0, &cp->page)) != 0)		return (ret);	memset(&dbt, 0, sizeof(DBT));	if ((ret = __db_ret(dbp, cp->page,	    cp->indx, &dbt, &dbc->my_rkey.data, &dbc->my_rkey.ulen)) != 0)		goto err;	ret = __memp_fput(mpf, cp->page, 0);	cp->page = NULL;	if (ret != 0)		return (ret);	if ((ret = __bam_search(dbc, PGNO_INVALID, &dbt,	    F_ISSET(dbc, DBC_RMW) ? S_FIND_WR : S_FIND,	    1, &recno, &exact)) != 0)		goto err;	ret = __db_retcopy(dbp->dbenv, data,	    &recno, sizeof(recno), &dbc->rdata->data, &dbc->rdata->ulen);	/* Release the stack. */err:	if ((t_ret = __bam_stkrel(dbc, 0)) != 0 && ret == 0)		ret = t_ret;	return (ret);}/* * __bam_c_writelock -- *	Upgrade the cursor to a write lock. */static int__bam_c_writelock(dbc)	DBC *dbc;{	BTREE_CURSOR *cp;	int ret;	cp = (BTREE_CURSOR *)dbc->internal;	if (cp->lock_mode == DB_LOCK_WRITE)		return (0);	/*	 * When writing to an off-page duplicate tree, we need to have the	 * appropriate page in the primary tree locked.  The general DBC	 * code calls us first with the primary cursor so we can acquire the	 * appropriate lock.	 */	ACQUIRE_WRITE_LOCK(dbc, ret);	return (ret);}/* * __bam_c_first -- *	Return the first record. */static int__bam_c_first(dbc)	DBC *dbc;{	BTREE_CURSOR *cp;	db_pgno_t pgno;	int ret;	cp = (BTREE_CURSOR *)dbc->internal;	ret = 0;	/* Walk down the left-hand side of the tree. */	for (pgno = cp->root;;) {		ACQUIRE_CUR_COUPLE(dbc, DB_LOCK_READ, pgno, ret);		if (ret != 0)			return (ret);		/* If we find a leaf page, we're done. */		if (ISLEAF(cp->page))			break;		pgno = GET_BINTERNAL(dbc->dbp, cp->page, 0)->pgno;	}	/* If we want a write lock instead of a read lock, get it now. */	if (F_ISSET(dbc, DBC_RMW)) {		ACQUIRE_WRITE_LOCK(dbc, ret);		if (ret != 0)			return (ret);	}	cp->indx = 0;	/* If on an empty page or a deleted record, move to the next one. */	if (NUM_ENT(cp->page) == 0 || IS_CUR_DELETED(dbc))		if ((ret = __bam_c_next(dbc, 0, 0)) != 0)			return (ret);	return (0);}/* * __bam_c_last -- *	Return the last record. */static int__bam_c_last(dbc)	DBC *dbc;{	BTREE_CURSOR *cp;	db_pgno_t pgno;	int ret;	cp = (BTREE_CURSOR *)dbc->internal;	ret = 0;	/* Walk down the right-hand side of the tree. */	for (pgno = cp->root;;) {		ACQUIRE_CUR_COUPLE(dbc, DB_LOCK_READ, pgno, ret);		if (ret != 0)			return (ret);		/* If we find a leaf page, we're done. */		if (ISLEAF(cp->page))			break;		pgno = GET_BINTERNAL(dbc->dbp, cp->page,		    NUM_ENT(cp->page) - O_INDX)->pgno;	}	/* If we want a write lock instead of a read lock, get it now. */	if (F_ISSET(dbc, DBC_RMW)) {		ACQUIRE_WRITE_LOCK(dbc, ret);		if (ret != 0)			return (ret);	}	cp->indx = NUM_ENT(cp->page) == 0 ? 0 :	    NUM_ENT(cp->page) -	    (TYPE(cp->page) == P_LBTREE ? P_INDX : O_INDX);	/* If on an empty page or a deleted record, move to the previous one. */	if (NUM_ENT(cp->page) == 0 || IS_CUR_DELETED(dbc))		if ((ret = __bam_c_prev(dbc)) != 0)			return (ret);	return (0);}/* * __bam_c_next -- *	Move to the next record. */static int__bam_c_next(dbc, initial_move, deleted_okay)	DBC *dbc;	int initial_move, deleted_okay;{	BTREE_CURSOR *cp;	db_indx_t adjust;	db_lockmode_t lock_mode;	db_pgno_t pgno;	int ret;	cp = (BTREE_CURSOR *)dbc->internal;	ret = 0;	/*	 * We're either moving through a page of duplicates or a btree leaf	 * page.	 *	 * !!!	 * This code handles empty pages and pages with only deleted entries.	 */	if (F_ISSET(dbc, DBC_OPD)) {		adjust = O_INDX;		lock_mode = DB_LOCK_NG;	} else {		adjust = dbc->dbtype == DB_BTREE ? P_INDX : O_INDX;		lock_mode =		    F_ISSET(dbc, DBC_RMW) ? DB_LOCK_WRITE : DB_LOCK_READ;	}	if (cp->page == NULL) {		ACQUIRE_CUR(dbc, lock_mode, cp->pgno, ret);		if (ret != 0)			return (ret);	}	if (initial_move)		cp->indx += adjust;	for (;;) {		/*		 * If at the end of the page, move to a subsequent page.		 *		 * !!!		 * Check for >= NUM_ENT.  If the original search landed us on		 * NUM_ENT, we may have incremented indx before the test.		 */		if (cp->indx >= NUM_ENT(cp->page)) {			if ((pgno			    = NEXT_PGNO(cp->page)) == PGNO_INVALID)				return (DB_NOTFOUND);			ACQUIRE_CUR(dbc, lock_mode, pgno, ret);			if (ret != 0)				return (ret);			cp->indx = 0;			continue;		}		if (!deleted_okay && IS_CUR_DELETED(dbc)) {			cp->indx += adjust;			continue;		}		break;	}	return (0);}/* * __bam_c_prev -- *	Move to the previous record. */static int__bam_c_prev(dbc)	DBC *dbc;{	BTREE_CURSOR *cp;	db_indx_t adjust;	db_lockmode_t lock_mode;	db_pgno_t pgno;	int ret;	cp = (BTREE_CURSOR *)dbc->internal;	ret = 0;	/*	 * We're either moving through a page of duplicates or a btree leaf	 * page.	 *	 * !!!	 * This code handles empty pages and pages with only deleted entries.	 */	if (F_ISSET(dbc, DBC_OPD)) {		adjust = O_INDX;		lock_mode = DB_LOCK_NG;	} else {		adjust = dbc->dbtype == DB_BTREE ? P_INDX : O_INDX;		lock_mode =		    F_ISSET(dbc, DBC_RMW) ? DB_LOCK_WRITE : DB_LOCK_READ;	}	if (cp->page == NULL) {		ACQUIRE_CUR(dbc, lock_mode, cp->pgno, ret);		if (ret != 0)			return (ret);	}	for (;;) {		/* If at the beginning of the page, move to a previous one. */		if (cp->indx == 0) {			if ((pgno =			    PREV_PGNO(cp->page)) == PGNO_INVALID)				return (DB_NOTFOUND);			ACQUIRE_CUR(dbc, lock_mode, pgno, ret);			if (ret != 0)				return (ret);			if ((cp->indx = NUM_ENT(cp->page)) == 0)				continue;		}		/* Ignore deleted records. */		cp->indx -= adjust;		if (IS_CUR_DELETED(dbc))			continue;		break;	}	return (0);}/* * __bam_c_search -- *	Move to a specified record. */static int__bam_c_search(dbc, root_pgno, key, flags, exactp)	DBC *dbc;	db_pgno_t root_pgno;	const DBT *key;	u_int32_t flags;	int *exactp;{	BTREE *t;	BTREE_CURSOR *cp;	DB *dbp;	PAGE *h;	db_indx_t indx, *inp;	db_pgno_t bt_lpgno;	db_recno_t recno;	u_int32_t sflags;	int cmp, ret, t_ret;	dbp = dbc->dbp;	cp = (BTREE_CURSOR *)dbc->internal;	t = dbp->bt_internal;	ret = 0;	/*	 * Find an entry in the database.  Discard any lock we currently hold,	 * we're going to search the tree.	 */	DISCARD_CUR(dbc, ret);	if (ret != 0)		return (ret);	switch (flags) {	case DB_SET_RECNO:		if ((ret = __ram_getno(dbc, key, &recno, 0)) != 0)			return (ret);		sflags = (F_ISSET(dbc, DBC_RMW) ? S_FIND_WR : S_FIND) | S_EXACT;		if ((ret = __bam_rsearch(dbc, &recno, sflags, 1, exactp)) != 0)			return (ret);		break;	case DB_SET:	case DB_GET_BOTH:		sflags = (F_ISSET(dbc, DBC_RMW) ? S_FIND_WR : S_FIND) | S_EXACT;		goto search;	case DB_GET_BOTH_RANGE:		sflags = (F_ISSET(dbc, DBC_RMW) ? S_FIND_WR : S_FIND);		goto search;	case DB_SET_RANGE:		sflags =		    (F_ISSET(dbc, DBC_RMW) ? S_WRITE : S_READ) | S_DUPFIRST;		goto search;	case DB_KEYFIRST:		sflags = S_KEYFIRST;		goto fast_search;	case DB_KEYLAST:	case DB_NODUPDATA:		sflags = S_KEYLAST;fast_search:	/*		 * If the application has a history of inserting into the first		 * or last pages of the database, we check those pages first to		 * avoid doing a full search.		 */		if (F_ISSET(dbc, DBC_OPD))			goto search;		/*		 * !!!		 * We do not mutex protect the t->bt_lpgno field, which means		 * that it can only be used in an advisory manner.  If we find		 * page we can use, great.  If we don't, we don't care, we do		 * it the slow way instead.  Regardless, copy it into a local		 * variable, otherwise we might acquire a lock for a page and		 * then read a different page because it changed underfoot.		 */		bt_lpgno = t->bt_lpgno;		/*		 * If the tree has no history of insertion, do it the slow way.		 */		if (bt_lpgno == PGNO_INVALID)			goto search;		/*		 * Lock and retrieve the page on which we last inserted.		 *		 * The page may not exist: if a transaction created the page		 * and then aborted, the page might have been truncated from		 * the end of the file.		 */		h = NULL;		ACQUIRE_CUR(dbc, DB_LOCK_WRITE, bt_lpgno, ret);		if (ret != 0) {			if (ret == DB_PAGE_NOTFOUND)				ret = 0;			goto fast_miss;		}		h = cp->page;		inp = P_INP(dbp, h);		/*		 * It's okay if the page type isn't right or it's empty, it		 * just means that the world changed.		 */		if (TYPE(h) != P_LBTREE || NUM_ENT(h) == 0)			goto fast_miss;		/* Verify that this page cannot have moved to another db. */		if (F_ISSET(dbp, DB_AM_SUBDB) &&		    log_compare(&t->bt_llsn, &LSN(h)) != 0)			goto fast_miss;		/*		 * What we do here is test to see if we're at the beginning or		 * end of the tree and if the new item sorts before/after the		 * first/last page entry.  We don't try and catch inserts into		 * the middle of the tree (although we could, as long as there		 * were two keys on the page and we saved both the index and		 * the page number of the last insert).		 */		if (h->next_pgno == PGNO_INVALID) {			indx = NUM_ENT(h) - P_INDX;			if ((ret = __bam_cmp(dbp,			    key, h, indx, t->bt_compare, &cmp)) != 0)				return (ret);			if (cmp < 0)				goto try_begin;			if (cmp > 0) {				indx += P_INDX;				goto fast_hit;			}			/*			 * Found a duplicate.  If doing DB_KEYLAST, we're at			 * the correct position, otherwis

⌨️ 快捷键说明

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