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

📄 db_am.c

📁 File system using stacked.
💻 C
📖 第 1 页 / 共 3 页
字号:
	u_int32_t flags;{	DB_ENV *dbenv;	DBC *pdbc, *sdbc;	DBT skey, key, data;	int build, ret, t_ret, txn_local;	dbenv = dbp->dbenv;	PANIC_CHECK(dbenv);	txn_local = 0;	pdbc = NULL;	memset(&key, 0, sizeof(DBT));	memset(&data, 0, sizeof(DBT));	memset(&skey, 0, sizeof(DBT));	if ((ret = __db_associatechk(dbp, sdbp, callback, flags)) != 0)		return (ret);	/*	 * Create a local transaction as necessary, check for consistent	 * transaction usage, and, if we have no transaction but do have	 * locking on, acquire a locker id for the handle lock acquisition.	 */	if (IS_AUTO_COMMIT(dbenv, txn, flags)) {		if ((ret = __db_txn_auto(dbp, &txn)) != 0)			return (ret);		txn_local = 1;	} else if (txn != NULL && !TXN_ON(dbenv))		return (__db_not_txn_env(dbenv));	/*	 * Check that if an open transaction is in progress, we're in it,	 * for other common transaction errors, and for concurrent associates.	 */	if ((ret = __db_check_txn(dbp, txn, DB_LOCK_INVALIDID, 0)) != 0)		return (ret);	sdbp->s_callback = callback;	sdbp->s_primary = dbp;	sdbp->stored_get = sdbp->get;	sdbp->get = __db_secondary_get;	sdbp->stored_close = sdbp->close;	sdbp->close = __db_secondary_close;	/*	 * Secondary cursors may have the primary's lock file ID, so we	 * need to make sure that no older cursors are lying around	 * when we make the transition.	 */	if (TAILQ_FIRST(&sdbp->active_queue) != NULL ||	    TAILQ_FIRST(&sdbp->join_queue) != NULL) {		__db_err(dbenv,    "Databases may not become secondary indices while cursors are open");		ret = EINVAL;		goto err;	}	while ((sdbc = TAILQ_FIRST(&sdbp->free_queue)) != NULL)		if ((ret = __db_c_destroy(sdbc)) != 0)			goto err;	F_SET(sdbp, DB_AM_SECONDARY);	/*	 * Check to see if the secondary is empty--and thus if we should	 * build it--before we link it in and risk making it show up in	 * other threads.	 */	build = 0;	if (LF_ISSET(DB_CREATE)) {		if ((ret = sdbp->cursor(sdbp, txn, &sdbc, 0)) != 0)			goto err;		memset(&key, 0, sizeof(DBT));		memset(&data, 0, sizeof(DBT));		/*		 * We don't care about key or data;  we're just doing		 * an existence check.		 */		F_SET(&key, DB_DBT_PARTIAL | DB_DBT_USERMEM);		F_SET(&data, DB_DBT_PARTIAL | DB_DBT_USERMEM);		if ((ret = sdbc->c_real_get(sdbc, &key, &data,		    (STD_LOCKING(sdbc) ? DB_RMW : 0) |		    DB_FIRST)) == DB_NOTFOUND) {			build = 1;			ret = 0;		}		/*		 * Secondary cursors have special refcounting close		 * methods.  Be careful.		 */		if ((t_ret = __db_c_close(sdbc)) != 0)			ret = t_ret;		if (ret != 0)			goto err;	}	/*	 * Add the secondary to the list on the primary.  Do it here	 * so that we see any updates that occur while we're walking	 * the primary.	 */	MUTEX_THREAD_LOCK(dbenv, dbp->mutexp);	/* See __db_s_next for an explanation of secondary refcounting. */	DB_ASSERT(sdbp->s_refcnt == 0);	sdbp->s_refcnt = 1;	LIST_INSERT_HEAD(&dbp->s_secondaries, sdbp, s_links);	MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp);	if (build) {		/*		 * We loop through the primary, putting each item we		 * find into the new secondary.		 *		 * If we're using CDB, opening these two cursors puts us		 * in a bit of a locking tangle:  CDB locks are done on the		 * primary, so that we stay deadlock-free, but that means		 * that updating the secondary while we have a read cursor		 * open on the primary will self-block.  To get around this,		 * we force the primary cursor to use the same locker ID		 * as the secondary, so they won't conflict.  This should		 * be harmless even if we're not using CDB.		 */		if ((ret = sdbp->cursor(sdbp, txn, &sdbc,		    CDB_LOCKING(sdbp->dbenv) ? DB_WRITECURSOR : 0)) != 0)			goto err;		if ((ret = __db_icursor(dbp,		    txn, dbp->type, PGNO_INVALID, 0, sdbc->locker, &pdbc)) != 0)			goto err;		/* Lock out other threads, now that we have a locker ID. */		dbp->associate_lid = sdbc->locker;		memset(&key, 0, sizeof(DBT));		memset(&data, 0, sizeof(DBT));		while ((ret = pdbc->c_get(pdbc, &key, &data, DB_NEXT)) == 0) {			memset(&skey, 0, sizeof(DBT));			if ((ret = callback(sdbp, &key, &data, &skey)) != 0) {				if (ret == DB_DONOTINDEX)					continue;				else					goto err;			}			if ((ret = sdbc->c_put(sdbc,			    &skey, &key, DB_UPDATE_SECONDARY)) != 0) {				FREE_IF_NEEDED(sdbp, &skey);				goto err;			}			FREE_IF_NEEDED(sdbp, &skey);		}		if (ret == DB_NOTFOUND)			ret = 0;		if ((ret = sdbc->c_close(sdbc)) != 0)			goto err;	}err:	if (pdbc != NULL && (t_ret = pdbc->c_close(pdbc)) != 0 && ret == 0)		ret = t_ret;	dbp->associate_lid = DB_LOCK_INVALIDID;	if (txn_local) {		if (ret == 0)			ret = txn->commit(txn, 0);		else			if ((t_ret = txn->abort(txn)) != 0)				ret = __db_panic(dbenv, t_ret);	}	return (ret);}/* * __db_pget -- *	Return a primary key/data pair given a secondary key. * * PUBLIC: int __db_pget __P((DB *, DB_TXN *, DBT *, DBT *, DBT *, u_int32_t)); */int__db_pget(dbp, txn, skey, pkey, data, flags)	DB *dbp;	DB_TXN *txn;	DBT *skey, *pkey, *data;	u_int32_t flags;{	DBC *dbc;	int ret, t_ret;	PANIC_CHECK(dbp->dbenv);	DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->pget");	if ((ret = __db_pgetchk(dbp, skey, pkey, data, flags)) != 0)		return (ret);	if ((ret = dbp->cursor(dbp, txn, &dbc, 0)) != 0)		return (ret);	SET_RET_MEM(dbc, dbp);	/*	 * The underlying cursor pget will fill in a default DBT for null	 * pkeys, and use the cursor's returned-key memory internally to	 * store any intermediate primary keys.  However, we've just set	 * the returned-key memory to the DB handle's key memory, which	 * is unsafe to use if the DB handle is threaded.  If the pkey	 * argument is NULL, use the DBC-owned returned-key memory	 * instead;  it'll go away when we close the cursor before we	 * return, but in this case that's just fine, as we're not	 * returning the primary key.	 */	if (pkey == NULL)		dbc->rkey = &dbc->my_rkey;	DEBUG_LREAD(dbc, txn, "__db_pget", skey, NULL, flags);	/*	 * The cursor is just a perfectly ordinary secondary database	 * cursor.  Call its c_pget() method to do the dirty work.	 */	if (flags == 0 || flags == DB_RMW)		flags |= DB_SET;	ret = dbc->c_pget(dbc, skey, pkey, data, flags);	if ((t_ret = __db_c_close(dbc)) != 0 && ret == 0)		ret = t_ret;	return (ret);}/* * __db_secondary_get -- *	This wrapper function for DB->pget() is the DB->get() function *	on a database which has been made into a secondary index. */static int__db_secondary_get(sdbp, txn, skey, data, flags)	DB *sdbp;	DB_TXN *txn;	DBT *skey, *data;	u_int32_t flags;{	DB_ASSERT(F_ISSET(sdbp, DB_AM_SECONDARY));	return (sdbp->pget(sdbp, txn, skey, NULL, data, flags));}/* * __db_secondary_close -- *	Wrapper function for DB->close() which we use on secondaries to *	manage refcounting and make sure we don't close them underneath *	a primary that is updating. */static int__db_secondary_close(sdbp, flags)	DB *sdbp;	u_int32_t flags;{	DB *primary;	int doclose;	doclose = 0;	primary = sdbp->s_primary;	MUTEX_THREAD_LOCK(primary->dbenv, primary->mutexp);	/*	 * Check the refcount--if it was at 1 when we were called, no	 * thread is currently updating this secondary through the primary,	 * so it's safe to close it for real.	 *	 * If it's not safe to do the close now, we do nothing;  the	 * database will actually be closed when the refcount is decremented,	 * which can happen in either __db_s_next or __db_s_done.	 */	DB_ASSERT(sdbp->s_refcnt != 0);	if (--sdbp->s_refcnt == 0) {		LIST_REMOVE(sdbp, s_links);		/* We don't want to call close while the mutex is held. */		doclose = 1;	}	MUTEX_THREAD_UNLOCK(primary->dbenv, primary->mutexp);	/*	 * sdbp->close is this function;  call the real one explicitly if	 * need be.	 */	return (doclose ? __db_close(sdbp, flags) : 0);}/* * __db_append_primary -- *	Perform the secondary index updates necessary to put(DB_APPEND) *	a record to a primary database. */static int__db_append_primary(dbc, key, data)	DBC *dbc;	DBT *key, *data;{	DB *dbp, *sdbp;	DBC *sdbc, *pdbc;	DBT oldpkey, pkey, pdata, skey;	int cmp, ret, t_ret;	dbp = dbc->dbp;	sdbp = NULL;	ret = 0;	/*	 * Worrying about partial appends seems a little like worrying	 * about Linear A character encodings.  But we support those	 * too if your application understands them.	 */	pdbc = NULL;	if (F_ISSET(data, DB_DBT_PARTIAL) || F_ISSET(key, DB_DBT_PARTIAL)) {		/*		 * The dbc we were passed is all set to pass things		 * back to the user;  we can't safely do a call on it.		 * Dup the cursor, grab the real data item (we don't		 * care what the key is--we've been passed it directly),		 * and use that instead of the data DBT we were passed.		 *		 * Note that we can get away with this simple get because		 * an appended item is by definition new, and the		 * correctly-constructed full data item from this partial		 * put is on the page waiting for us.		 */		if ((ret = __db_c_idup(dbc, &pdbc, DB_POSITIONI)) != 0)			return (ret);		memset(&pkey, 0, sizeof(DBT));		memset(&pdata, 0, sizeof(DBT));		if ((ret = pdbc->c_get(pdbc, &pkey, &pdata, DB_CURRENT)) != 0)			goto err;		key = &pkey;		data = &pdata;	}	/*	 * Loop through the secondary indices, putting a new item in	 * each that points to the appended item.	 *	 * This is much like the loop in "step 3" in __db_c_put, so	 * I'm not commenting heavily here;  it was unclean to excerpt	 * just that section into a common function, but the basic	 * overview is the same here.	 */	for (sdbp = __db_s_first(dbp);	    sdbp != NULL && ret == 0; ret = __db_s_next(&sdbp)) {		memset(&skey, 0, sizeof(DBT));		if ((ret = sdbp->s_callback(sdbp, key, data, &skey)) != 0) {			if (ret == DB_DONOTINDEX)				continue;			else				goto err;		}		if ((ret = __db_icursor(sdbp, dbc->txn, sdbp->type,		    PGNO_INVALID, 0, dbc->locker, &sdbc)) != 0) {			FREE_IF_NEEDED(sdbp, &skey);			goto err;		}		if (CDB_LOCKING(sdbp->dbenv)) {			DB_ASSERT(sdbc->mylock.off == LOCK_INVALID);			F_SET(sdbc, DBC_WRITER);		}		/*		 * Since we know we have a new primary key, it can't be a		 * duplicate duplicate in the secondary.  It can be a		 * duplicate in a secondary that doesn't support duplicates,		 * however, so we need to be careful to avoid an overwrite		 * (which would corrupt our index).		 */		if (!F_ISSET(sdbp, DB_AM_DUP)) {			memset(&oldpkey, 0, sizeof(DBT));			F_SET(&oldpkey, DB_DBT_MALLOC);			ret = sdbc->c_real_get(sdbc, &skey, &oldpkey,			    DB_SET | (STD_LOCKING(dbc) ? DB_RMW : 0));			if (ret == 0) {				cmp = __bam_defcmp(sdbp, &oldpkey, key);				/*				 * XXX				 * This needs to use the right free function				 * as soon as this is possible.				 */				__os_ufree(sdbp->dbenv,				    oldpkey.data);				if (cmp != 0) {					__db_err(sdbp->dbenv, "%s%s",			    "Append results in a non-unique secondary key in",			    " an index not configured to support duplicates");					ret = EINVAL;					goto err1;				}			} else if (ret != DB_NOTFOUND && ret != DB_KEYEMPTY)				goto err1;		}		ret = sdbc->c_put(sdbc, &skey, key, DB_UPDATE_SECONDARY);err1:		FREE_IF_NEEDED(sdbp, &skey);		if ((t_ret = sdbc->c_close(sdbc)) != 0 && ret == 0)			ret = t_ret;		if (ret != 0)			goto err;	}err:	if (pdbc != NULL && (t_ret = pdbc->c_close(pdbc)) != 0 && ret == 0)		ret = t_ret;	if (sdbp != NULL && (t_ret = __db_s_done(sdbp)) != 0 && ret == 0)		ret = t_ret;	return (ret);}

⌨️ 快捷键说明

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