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

📄 db_cam.c

📁 这是linux下运行的mysql软件包,可用于linux 下安装 php + mysql + apach 的网络配置
💻 C
📖 第 1 页 / 共 5 页
字号:
	PANIC_CHECK(dbp->dbenv);	/* Check for invalid flags. */	if ((ret = __db_cputchk(dbp,	    key, data, flags, IS_INITIALIZED(dbc_arg))) != 0)		return (ret);	/* Check for consistent transaction usage. */	if ((ret = __db_check_txn(dbp, dbc_arg->txn, dbc_arg->locker, 0)) != 0)		return (ret);	/*	 * Putting to secondary indices is forbidden;  when we need	 * to internally update one, we'll call this with a private	 * synonym for DB_KEYLAST, DB_UPDATE_SECONDARY, which does	 * the right thing but won't return an error from cputchk().	 */	if (flags == DB_UPDATE_SECONDARY)		flags = DB_KEYLAST;	DEBUG_LWRITE(dbc_arg, dbc_arg->txn, "db_c_put",	    flags == DB_KEYFIRST || flags == DB_KEYLAST ||	    flags == DB_NODUPDATA ? key : NULL, data, flags);	CDB_LOCKING_INIT(dbp, dbc_arg);	/*	 * Check to see if we are a primary and have secondary indices.	 * If we are not, we save ourselves a good bit of trouble and	 * just skip to the "normal" put.	 */	if (LIST_FIRST(&dbp->s_secondaries) == NULL)		goto skip_s_update;	/*	 * We have at least one secondary which we may need to update.	 *	 * There is a rather vile locking issue here.  Secondary gets	 * will always involve acquiring a read lock in the secondary,	 * then acquiring a read lock in the primary.  Ideally, we	 * would likewise perform puts by updating all the secondaries	 * first, then doing the actual put in the primary, to avoid	 * deadlock (since having multiple threads doing secondary	 * gets and puts simultaneously is probably a common case).	 *	 * However, if this put is a put-overwrite--and we have no way to	 * tell in advance whether it will be--we may need to delete	 * an outdated secondary key.  In order to find that old	 * secondary key, we need to get the record we're overwriting,	 * before we overwrite it.	 *	 * (XXX: It would be nice to avoid this extra get, and have the	 * underlying put routines somehow pass us the old record	 * since they need to traverse the tree anyway.  I'm saving	 * this optimization for later, as it's a lot of work, and it	 * would be hard to fit into this locking paradigm anyway.)	 *	 * The simple thing to do would be to go get the old record before	 * we do anything else.  Unfortunately, though, doing so would	 * violate our "secondary, then primary" lock acquisition	 * ordering--even in the common case where no old primary record	 * exists, we'll still acquire and keep a lock on the page where	 * we're about to do the primary insert.	 *	 * To get around this, we do the following gyrations, which	 * hopefully solve this problem in the common case:	 *	 * 1) If this is a c_put(DB_CURRENT), go ahead and get the	 *    old record.  We already hold the lock on this page in	 *    the primary, so no harm done, and we'll need the primary	 *    key (which we weren't passed in this case) to do any	 *    secondary puts anyway.	 *	 * 2) If we're doing a partial put, we need to perform the	 *    get on the primary key right away, since we don't have	 *    the whole datum that the secondary key is based on.	 *    We may also need to pad out the record if the primary	 *    has a fixed record length.	 *	 * 3) Loop through the secondary indices, putting into each a	 *    new secondary key that corresponds to the new record.	 *	 * 4) If we haven't done so in (1) or (2), get the old primary	 *    key/data pair.  If one does not exist--the common case--we're	 *    done with secondary indices, and can go straight on to the	 *    primary put.	 *	 * 5) If we do have an old primary key/data pair, however, we need	 *    to loop through all the secondaries a second time and delete	 *    the old secondary in each.	 */	memset(&pkey, 0, sizeof(DBT));	memset(&olddata, 0, sizeof(DBT));	have_oldrec = nodel = 0;	/*	 * Primary indices can't have duplicates, so only DB_CURRENT,	 * DB_KEYFIRST, and DB_KEYLAST make any sense.  Other flags	 * should have been caught by the checking routine, but	 * add a sprinkling of paranoia.	 */	DB_ASSERT(flags == DB_CURRENT ||	    flags == DB_KEYFIRST || flags == DB_KEYLAST);	/*	 * We'll want to use DB_RMW in a few places, but it's only legal	 * when locking is on.	 */	rmw = STD_LOCKING(dbc_arg) ? DB_RMW : 0;	if (flags == DB_CURRENT) {		/* Step 1. */		/*		 * This is safe to do on the cursor we already have;		 * error or no, it won't move.		 *		 * We use DB_RMW for all of these gets because we'll be		 * writing soon enough in the "normal" put code.  In		 * transactional databases we'll hold those write locks		 * even if we close the cursor we're reading with.		 */		ret = dbc_arg->c_get(dbc_arg,		    &pkey, &olddata, rmw | DB_CURRENT);		if (ret == DB_KEYEMPTY) {			nodel = 1;	 /*					  * We know we don't need a delete					  * in the secondary.					  */			have_oldrec = 1; /* We've looked for the old record. */		} else if (ret != 0)			goto err;		else			have_oldrec = 1;	} else {		/* So we can just use &pkey everywhere instead of key. */		pkey.data = key->data;		pkey.size = key->size;	}	/*	 * Check for partial puts (step 2).	 */	if (F_ISSET(data, DB_DBT_PARTIAL)) {		if (!have_oldrec && !nodel) {			/*			 * We're going to have to search the tree for the			 * specified key.  Dup a cursor (so we have the same			 * locking info) and do a c_get.			 */			if ((ret = __db_c_idup(dbc_arg, &pdbc, 0)) != 0)				goto err;			/* We should have gotten DB_CURRENT in step 1. */			DB_ASSERT(flags != DB_CURRENT);			ret = pdbc->c_get(pdbc,			    &pkey, &olddata, rmw | DB_SET);			if (ret == DB_KEYEMPTY || ret == DB_NOTFOUND) {				nodel = 1;				ret = 0;			}			if ((t_ret = pdbc->c_close(pdbc)) != 0)				ret = t_ret;			if (ret != 0)				goto err;			have_oldrec = 1;		}		/*		 * Now build the new datum from olddata and the partial		 * data we were given.		 */		if ((ret =		    __db_buildpartial(dbp, &olddata, data, &newdata)) != 0)			goto err;		ispartial = 1;	} else		ispartial = 0;	/*	 * Handle fixed-length records.  If the primary database has	 * fixed-length records, we need to pad out the datum before	 * we pass it into the callback function;  we always index the	 * "real" record.	 */	if ((dbp->type == DB_RECNO && F_ISSET(dbp, DB_AM_FIXEDLEN)) ||	    (dbp->type == DB_QUEUE)) {		if (dbp->type == DB_QUEUE) {			re_len = ((QUEUE *)dbp->q_internal)->re_len;			re_pad = ((QUEUE *)dbp->q_internal)->re_pad;		} else {			re_len = ((BTREE *)dbp->bt_internal)->re_len;			re_pad = ((BTREE *)dbp->bt_internal)->re_pad;		}		size = ispartial ? newdata.size : data->size;		if (size > re_len) {			__db_err(dbp->dbenv,			    "Length improper for fixed length record %lu",			    (u_long)size);			ret = EINVAL;			goto err;		} else if (size < re_len) {			/*			 * If we're not doing a partial put, copy			 * data->data into newdata.data, then pad out			 * newdata.data.			 *			 * If we're doing a partial put, the data			 * we want are already in newdata.data;  we			 * just need to pad.			 *			 * Either way, realloc is safe.			 */			if ((ret = __os_realloc(dbp->dbenv, re_len,			    &newdata.data)) != 0)				goto err;			if (!ispartial)				memcpy(newdata.data, data->data, size);			memset((u_int8_t *)newdata.data + size, re_pad,			    re_len - size);			newdata.size = re_len;			ispartial = 1;		}	}	/*	 * Loop through the secondaries.  (Step 3.)	 *	 * Note that __db_s_first and __db_s_next will take care of	 * thread-locking and refcounting issues.	 */	for (sdbp = __db_s_first(dbp);	    sdbp != NULL && ret == 0; ret = __db_s_next(&sdbp)) {		/*		 * Call the callback for this secondary, to get the		 * appropriate secondary key.		 */		memset(&skey, 0, sizeof(DBT));		if ((ret = sdbp->s_callback(sdbp,		    &pkey, ispartial ? &newdata : data, &skey)) != 0) {			if (ret == DB_DONOTINDEX)				/*				 * The callback returned a null value--don't				 * put this key in the secondary.  Just				 * move on to the next one--we'll handle				 * any necessary deletes in step 5.				 */				continue;			else				goto err;		}		/*		 * Save the DBT we just got back from the callback function		 * off;  we want to pass its value into c_get functions		 * that may stomp on a buffer the callback function		 * allocated.		 */		memset(&save_skey, 0, sizeof(DBT));	/* Paranoia. */		save_skey = skey;		/*		 * Open a cursor in this secondary.		 *		 * Use the same locker ID as our primary cursor, so that		 * we're guaranteed that the locks don't conflict (e.g. in CDB		 * or if we're subdatabases that share and want to lock a		 * metadata page).		 */		if ((ret = __db_icursor(sdbp, dbc_arg->txn, sdbp->type,		    PGNO_INVALID, 0, dbc_arg->locker, &sdbc)) != 0)			goto err;		/*		 * If we're in CDB, updates will fail since the new cursor		 * isn't a writer.  However, we hold the WRITE lock in the		 * primary and will for as long as our new cursor lasts,		 * and the primary and secondary share a lock file ID,		 * so it's safe to consider this a WRITER.  The close		 * routine won't try to put anything because we don't		 * really have a lock.		 */		if (CDB_LOCKING(sdbp->dbenv)) {			DB_ASSERT(sdbc->mylock.off == LOCK_INVALID);			F_SET(sdbc, DBC_WRITER);		}		/*		 * There are three cases here--		 * 1) The secondary supports sorted duplicates.		 *	If we attempt to put a secondary/primary pair		 *	that already exists, that's a duplicate duplicate,		 *	and c_put will return DB_KEYEXIST (see __db_duperr).		 *	This will leave us with exactly one copy of the		 *	secondary/primary pair, and this is just right--we'll		 *	avoid deleting it later, as the old and new secondaries		 *	will match (since the old secondary is the dup dup		 *	that's already there).		 * 2) The secondary supports duplicates, but they're not		 *	sorted.  We need to avoid putting a duplicate		 *	duplicate, because the matching old and new secondaries		 *	will prevent us from deleting anything and we'll		 *	wind up with two secondary records that point to the		 *	same primary key.  Do a c_get(DB_GET_BOTH);  if		 *	that returns 0, skip the put.		 * 3) The secondary doesn't support duplicates at all.		 *	In this case, secondary keys must be unique;  if		 *	another primary key already exists for this		 *	secondary key, we have to either overwrite it or		 *	not put this one, and in either case we've		 *	corrupted the secondary index.  Do a c_get(DB_SET).		 *	If the secondary/primary pair already exists, do		 *	nothing;  if the secondary exists with a different		 *	primary, return an error;  and if the secondary		 *	does not exist, put it.		 */		if (!F_ISSET(sdbp, DB_AM_DUP)) {			/* Case 3. */			memset(&oldpkey, 0, sizeof(DBT));			F_SET(&oldpkey, DB_DBT_MALLOC);			ret = sdbc->c_real_get(sdbc,			    &skey, &oldpkey, rmw | DB_SET);			if (ret == 0) {				cmp = __bam_defcmp(sdbp, &oldpkey, &pkey);				__os_ufree(sdbp->dbenv, oldpkey.data);				if (cmp != 0) {					__db_err(sdbp->dbenv, "%s%s",			    "Put results in a non-unique secondary key in an ",			    "index not configured to support duplicates");					ret = EINVAL;					goto skipput;				}			} else if (ret != DB_NOTFOUND && ret != DB_KEYEMPTY)				goto skipput;		} else if (!F_ISSET(sdbp, DB_AM_DUPSORT))			/* Case 2. */			if ((ret = sdbc->c_real_get(sdbc,			    &skey, &pkey, rmw | DB_GET_BOTH)) == 0)				goto skipput;		ret = sdbc->c_put(sdbc, &skey, &pkey, DB_UPDATE_SECONDARY);		/*		 * We don't know yet whether this was a put-overwrite that		 * in fact changed nothing.  If it was, we may get DB_KEYEXIST.		 * This is not an error.		 */		if (ret == DB_KEYEXIST)			ret = 0;skipput:	FREE_IF_NEEDED(sdbp, &save_skey)		if ((t_ret = sdbc->c_close(sdbc)) != 0)			ret = t_ret;		if (ret != 0)			goto err;	}	if (ret != 0)		goto err;	/* If still necessary, go get the old primary key/data.  (Step 4.) */	if (!have_oldrec) {		/* See the comments in step 2.  This is real familiar. */		if ((ret = __db_c_idup(dbc_arg, &pdbc, 0)) != 0)			goto err;		DB_ASSERT(flags != DB_CURRENT);		pkey.data = key->data;		pkey.size = key->size;		ret = pdbc->c_get(pdbc, &pkey, &olddata, rmw | DB_SET);		if (ret == DB_KEYEMPTY || ret == DB_NOTFOUND) {			nodel = 1;			ret = 0;		}		if ((t_ret = pdbc->c_close(pdbc)) != 0)			ret = t_ret;		if (ret != 0)			goto err;		have_oldrec = 1;	}	/*	 * If we don't follow this goto, we do in fact have an old record	 * we may need to go delete.  (Step 5).	 */	if (nodel)		goto skip_s_update;	for (sdbp = __db_s_first(dbp);	    sdbp != NULL && ret == 0; ret = __db_s_next(&sdbp)) {		/*		 * Call the callback for this secondary to get the		 * old secondary key.		 */		memset(&oldskey, 0, sizeof(DBT));		if ((ret = sdbp->s_callback(sdbp,		    &pkey, &olddata, &oldskey)) != 0) {			if (ret == DB_DONOTINDEX)				/*				 * The callback returned a null value--there's				 * nothing to delete.  Go on to the next				 * secondary.				 */				continue;			else				goto err;		}		if ((ret = sdbp->s_callback(sdbp,		    &pkey, ispartial ? &newdata : data, &skey)) != 0 &&		    ret != DB_DONOTINDEX)			goto err;		/*		 * If there is no new secondary key, or if the old secondary		 * key is different from the new secondary key, then		 * we need to delete the old one.		 *		 * Note that bt_compare is (and must be) set no matter		 * what access method we're in.		 */		sdbc = NULL;		if (ret == DB_DONOTINDEX ||		    ((BTREE *)sdbp->bt_internal)->bt_compare(sdbp,		    &oldskey, &skey) != 0) {			if ((ret = __db_icursor(sdbp, dbc_arg->txn, sdbp->type,			    PGNO_INVALID, 0, dbc_arg->locker, &sdbc)) != 0)				goto err;			if (CDB_LOCKING(sdbp->dbenv)) {				DB_ASSERT(sdbc->mylock.off == LOCK_INVALID);				F_SET(sdbc, DBC_WRITER);			}			/*			 * Don't let c_get(DB_GET_BOTH) stomp on			 * any secondary key value that the callback			 * function may have allocated.  Use a temp			 * DBT instead.			 */			memset(&temp, 0, sizeof(DBT));			temp.data = oldskey.data;			temp.size = oldskey.size;			if ((ret = sdbc->c_real_get(sdbc,			    &temp, &pkey, rmw | DB_GET_BOTH)) == 0)				ret = sdbc->c_del(sdbc, DB_UPDATE_SECONDARY);		}		FREE_IF_NEEDED(sdbp, &skey);		FREE_IF_NEEDED(sdbp, &oldskey);		if (sdbc != NULL && (t_ret = sdbc->c_close(sdbc)) != 0)			ret = t_ret;		if (ret != 0)			goto err;	}	/* Secondary index updates are now done.  On to the "real" stuff. */

⌨️ 快捷键说明

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