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

📄 lock.c

📁 这是linux下运行的mysql软件包,可用于linux 下安装 php + mysql + apach 的网络配置
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * __lock_inherit_timeout *		-- inherit timeout values from parent locker. * This is called from the transaction system.  This will * return EINVAL if the parent does not exist or did not * have a current txn timeout set. * * PUBLIC: int __lock_inherit_timeout __P(( DB_ENV *, u_int32_t, u_int32_t)); */int__lock_inherit_timeout(dbenv, parent, locker)	DB_ENV *dbenv;	u_int32_t parent, locker;{	DB_LOCKER *parent_locker, *sh_locker;	DB_LOCKREGION *region;	DB_LOCKTAB *lt;	u_int32_t locker_ndx;	int ret;	lt = dbenv->lk_handle;	region = lt->reginfo.primary;	ret = 0;	LOCKREGION(dbenv, lt);	/* If the parent does not exist, we are done. */	LOCKER_LOCK(lt, region, parent, locker_ndx);	if ((ret = __lock_getlocker(lt,	    parent, locker_ndx, 0, &parent_locker)) != 0)		goto err;	/*	 * If the parent is not there yet, thats ok.  If it	 * does not have any timouts set, then avoid creating	 * the child locker at this point.	 */	if (parent_locker == NULL ||	    (LOCK_TIME_ISVALID(&parent_locker->tx_expire) &&	    !F_ISSET(parent_locker, DB_LOCKER_TIMEOUT))) {		ret = EINVAL;		goto done;	}	LOCKER_LOCK(lt, region, locker, locker_ndx);	if ((ret = __lock_getlocker(lt,	    locker, locker_ndx, 1, &sh_locker)) != 0)		goto err;	sh_locker->tx_expire = parent_locker->tx_expire;	if (F_ISSET(parent_locker, DB_LOCKER_TIMEOUT)) {		sh_locker->lk_timeout = parent_locker->lk_timeout;		F_SET(sh_locker, DB_LOCKER_TIMEOUT);		if (!LOCK_TIME_ISVALID(&parent_locker->tx_expire))			ret = EINVAL;	}done:err:	UNLOCKREGION(dbenv, lt);	return (ret);}/* * __lock_getlocker -- *	Get a locker in the locker hash table.  The create parameter * indicates if the locker should be created if it doesn't exist in * the table. * * This must be called with the locker bucket locked. * * PUBLIC: int __lock_getlocker __P((DB_LOCKTAB *, * PUBLIC:     u_int32_t, u_int32_t, int, DB_LOCKER **)); */int__lock_getlocker(lt, locker, indx, create, retp)	DB_LOCKTAB *lt;	u_int32_t locker, indx;	int create;	DB_LOCKER **retp;{	DB_ENV *dbenv;	DB_LOCKER *sh_locker;	DB_LOCKREGION *region;	dbenv = lt->dbenv;	region = lt->reginfo.primary;	HASHLOOKUP(lt->locker_tab,	    indx, __db_locker, links, locker, sh_locker, __lock_locker_cmp);	/*	 * If we found the locker, then we can just return it.  If	 * we didn't find the locker, then we need to create it.	 */	if (sh_locker == NULL && create) {		/* Create new locker and then insert it into hash table. */		if ((sh_locker = SH_TAILQ_FIRST(		    &region->free_lockers, __db_locker)) == NULL) {			__db_err(dbenv, __db_lock_err, "locker entries");			return (ENOMEM);		}		SH_TAILQ_REMOVE(		    &region->free_lockers, sh_locker, links, __db_locker);		if (++region->stat.st_nlockers > region->stat.st_maxnlockers)			region->stat.st_maxnlockers = region->stat.st_nlockers;		sh_locker->id = locker;		sh_locker->dd_id = 0;		sh_locker->master_locker = INVALID_ROFF;		sh_locker->parent_locker = INVALID_ROFF;		SH_LIST_INIT(&sh_locker->child_locker);		sh_locker->flags = 0;		SH_LIST_INIT(&sh_locker->heldby);		sh_locker->nlocks = 0;		sh_locker->nwrites = 0;		sh_locker->lk_timeout = 0;		LOCK_SET_TIME_INVALID(&sh_locker->tx_expire);		if (locker < TXN_MINIMUM && region->tx_timeout != 0)			__lock_expires(dbenv,			    &sh_locker->tx_expire, region->tx_timeout);		LOCK_SET_TIME_INVALID(&sh_locker->lk_expire);		HASHINSERT(lt->locker_tab, indx, __db_locker, links, sh_locker);		SH_TAILQ_INSERT_HEAD(&region->lockers,		    sh_locker, ulinks, __db_locker);	}	*retp = sh_locker;	return (0);}/* * __lock_getobj -- *	Get an object in the object hash table.  The create parameter * indicates if the object should be created if it doesn't exist in * the table. * * This must be called with the object bucket locked. */static int__lock_getobj(lt, obj, ndx, create, retp)	DB_LOCKTAB *lt;	const DBT *obj;	u_int32_t ndx;	int create;	DB_LOCKOBJ **retp;{	DB_ENV *dbenv;	DB_LOCKOBJ *sh_obj;	DB_LOCKREGION *region;	int ret;	void *p;	dbenv = lt->dbenv;	region = lt->reginfo.primary;	/* Look up the object in the hash table. */	HASHLOOKUP(lt->obj_tab,	    ndx, __db_lockobj, links, obj, sh_obj, __lock_cmp);	/*	 * If we found the object, then we can just return it.  If	 * we didn't find the object, then we need to create it.	 */	if (sh_obj == NULL && create) {		/* Create new object and then insert it into hash table. */		if ((sh_obj =		    SH_TAILQ_FIRST(&region->free_objs, __db_lockobj)) == NULL) {			__db_err(lt->dbenv, __db_lock_err, "object entries");			ret = ENOMEM;			goto err;		}		/*		 * If we can fit this object in the structure, do so instead		 * of shalloc-ing space for it.		 */		if (obj->size <= sizeof(sh_obj->objdata))			p = sh_obj->objdata;		else if ((ret = __db_shalloc(		    lt->reginfo.addr, obj->size, 0, &p)) != 0) {			__db_err(dbenv, "No space for lock object storage");			goto err;		}		memcpy(p, obj->data, obj->size);		SH_TAILQ_REMOVE(		    &region->free_objs, sh_obj, links, __db_lockobj);		if (++region->stat.st_nobjects > region->stat.st_maxnobjects)			region->stat.st_maxnobjects = region->stat.st_nobjects;		SH_TAILQ_INIT(&sh_obj->waiters);		SH_TAILQ_INIT(&sh_obj->holders);		sh_obj->lockobj.size = obj->size;		sh_obj->lockobj.off = SH_PTR_TO_OFF(&sh_obj->lockobj, p);		HASHINSERT(lt->obj_tab, ndx, __db_lockobj, links, sh_obj);	}	*retp = sh_obj;	return (0);err:	return (ret);}/* * __lock_is_parent -- *	Given a locker and a transaction, return 1 if the locker is * an ancestor of the designcated transaction.  This is used to determine * if we should grant locks that appear to conflict, but don't because * the lock is already held by an ancestor. */static int__lock_is_parent(lt, locker, sh_locker)	DB_LOCKTAB *lt;	u_int32_t locker;	DB_LOCKER *sh_locker;{	DB_LOCKER *parent;	parent = sh_locker;	while (parent->parent_locker != INVALID_ROFF) {		parent = (DB_LOCKER *)		    R_ADDR(&lt->reginfo, parent->parent_locker);		if (parent->id == locker)			return (1);	}	return (0);}/* * __lock_promote -- * * Look through the waiters and holders lists and decide which (if any) * locks can be promoted.   Promote any that are eligible. * * PUBLIC: int __lock_promote __P((DB_LOCKTAB *, DB_LOCKOBJ *, u_int32_t)); */int__lock_promote(lt, obj, flags)	DB_LOCKTAB *lt;	DB_LOCKOBJ *obj;	u_int32_t flags;{	struct __db_lock *lp_w, *lp_h, *next_waiter;	DB_LOCKER *sh_locker;	DB_LOCKREGION *region;	u_int32_t locker_ndx;	int had_waiters, state_changed;	region = lt->reginfo.primary;	had_waiters = 0;	/*	 * We need to do lock promotion.  We also need to determine if we're	 * going to need to run the deadlock detector again.  If we release	 * locks, and there are waiters, but no one gets promoted, then we	 * haven't fundamentally changed the lockmgr state, so we may still	 * have a deadlock and we have to run again.  However, if there were	 * no waiters, or we actually promoted someone, then we are OK and we	 * don't have to run it immediately.	 *	 * During promotion, we look for state changes so we can return this	 * information to the caller.	 */	for (lp_w = SH_TAILQ_FIRST(&obj->waiters, __db_lock),	    state_changed = lp_w == NULL;	    lp_w != NULL;	    lp_w = next_waiter) {		had_waiters = 1;		next_waiter = SH_TAILQ_NEXT(lp_w, links, __db_lock);		/* Waiter may have aborted or expired. */		if (lp_w->status != DB_LSTAT_WAITING)			continue;		/* Are we switching locks? */		if (LF_ISSET(DB_LOCK_NOWAITERS) && lp_w->mode == DB_LOCK_WAIT)			continue;		if (LF_ISSET(DB_LOCK_REMOVE)) {			__lock_remove_waiter(lt, obj, lp_w, DB_LSTAT_NOTEXIST);			continue;		}		for (lp_h = SH_TAILQ_FIRST(&obj->holders, __db_lock);		    lp_h != NULL;		    lp_h = SH_TAILQ_NEXT(lp_h, links, __db_lock)) {			if (lp_h->holder != lp_w->holder &&			    CONFLICTS(lt, region, lp_h->mode, lp_w->mode)) {				LOCKER_LOCK(lt,				    region, lp_w->holder, locker_ndx);				if ((__lock_getlocker(lt, lp_w->holder,				    locker_ndx, 0, &sh_locker)) != 0) {					DB_ASSERT(0);					break;				}				if (!__lock_is_parent(lt,				    lp_h->holder, sh_locker))					break;			}		}		if (lp_h != NULL)	/* Found a conflict. */			break;		/* No conflict, promote the waiting lock. */		SH_TAILQ_REMOVE(&obj->waiters, lp_w, links, __db_lock);		lp_w->status = DB_LSTAT_PENDING;		SH_TAILQ_INSERT_TAIL(&obj->holders, lp_w, links);		/* Wake up waiter. */		MUTEX_UNLOCK(lt->dbenv, &lp_w->mutex);		state_changed = 1;	}	/*	 * If this object had waiters and doesn't any more, then we need	 * to remove it from the dd_obj list.	 */	if (had_waiters && SH_TAILQ_FIRST(&obj->waiters, __db_lock) == NULL)		SH_TAILQ_REMOVE(&region->dd_objs, obj, dd_links, __db_lockobj);	return (state_changed);}/* * __lock_remove_waiter -- *	Any lock on the waitlist has a process waiting for it.  Therefore, * we can't return the lock to the freelist immediately.  Instead, we can * remove the lock from the list of waiters, set the status field of the * lock, and then let the process waking up return the lock to the * free list. * * This must be called with the Object bucket locked. */static void__lock_remove_waiter(lt, sh_obj, lockp, status)	DB_LOCKTAB *lt;	DB_LOCKOBJ *sh_obj;	struct __db_lock *lockp;	db_status_t status;{	DB_LOCKREGION *region;	int do_wakeup;	region = lt->reginfo.primary;	do_wakeup = lockp->status == DB_LSTAT_WAITING;	SH_TAILQ_REMOVE(&sh_obj->waiters, lockp, links, __db_lock);	lockp->links.stqe_prev = -1;	lockp->status = status;	if (SH_TAILQ_FIRST(&sh_obj->waiters, __db_lock) == NULL)		SH_TAILQ_REMOVE(		    &region->dd_objs,		    sh_obj, dd_links, __db_lockobj);	/*	 * Wake whoever is waiting on this lock.	 *	 * The MUTEX_UNLOCK macro normally resolves to a single argument,	 * keep the compiler quiet.	 */	if (do_wakeup)		MUTEX_UNLOCK(lt->dbenv, &lockp->mutex);}/* * __lock_expires -- set the expire time given the time to live. * We assume that if timevalp is set then it contains "now". * This avoids repeated system calls to get the time. */static void__lock_expires(dbenv, timevalp, timeout)	DB_ENV *dbenv;	db_timeval_t *timevalp;	db_timeout_t timeout;{	if (!LOCK_TIME_ISVALID(timevalp))		__os_clock(dbenv, &timevalp->tv_sec, &timevalp->tv_usec);	if (timeout > 1000000) {		timevalp->tv_sec += timeout / 1000000;		timevalp->tv_usec += timeout % 1000000;	} else		timevalp->tv_usec += timeout;	if (timevalp->tv_usec > 1000000) {		timevalp->tv_sec++;		timevalp->tv_usec -= 1000000;	}}/* * __lock_expired -- determine if a lock has expired. * * PUBLIC: int __lock_expired __P((DB_ENV *, db_timeval_t *, db_timeval_t *)); */int__lock_expired(dbenv, now, timevalp)	DB_ENV *dbenv;	db_timeval_t *now, *timevalp;{	if (!LOCK_TIME_ISVALID(timevalp))		return (0);	if (!LOCK_TIME_ISVALID(now))		__os_clock(dbenv, &now->tv_sec, &now->tv_usec);	return (now->tv_sec > timevalp->tv_sec ||	    (now->tv_sec == timevalp->tv_sec &&	    now->tv_usec >= timevalp->tv_usec));}/* * __lock_trade -- * * Trade locker ids on a lock.  This is used to reassign file locks from * a transactional locker id to a long-lived locker id.  This should be * called with the region mutex held. */static int__lock_trade(dbenv, lock, new_locker)	DB_ENV *dbenv;	DB_LOCK *lock;	u_int32_t new_locker;{	struct __db_lock *lp;	DB_LOCKREGION *region;	DB_LOCKTAB *lt;	DB_LOCKER *sh_locker;	int ret;	u_int32_t locker_ndx;	lt = dbenv->lk_handle;	region = lt->reginfo.primary;	lp = (struct __db_lock *)R_ADDR(&lt->reginfo, lock->off);	/* If the lock is already released, simply return. */	if (lp->gen != lock->gen)		return (DB_NOTFOUND);	/* Make sure that we can get new locker and add this lock to it. */	LOCKER_LOCK(lt, region, new_locker, locker_ndx);	if ((ret =	    __lock_getlocker(lt, new_locker, locker_ndx, 0, &sh_locker)) != 0)		return (ret);	if (sh_locker == NULL) {		__db_err(dbenv, "Locker does not exist");		return (EINVAL);	}	/* Remove the lock from its current locker. */	if ((ret = __lock_checklocker(lt, lp, lp->holder, DB_LOCK_UNLINK)) != 0)		return (ret);	/* Add lock to its new locker. */	SH_LIST_INSERT_HEAD(&sh_locker->heldby, lp, locker_links, __db_lock);	sh_locker->nlocks++;	if (IS_WRITELOCK(lp->mode))		sh_locker->nwrites++;	lp->holder = new_locker;	return (0);}

⌨️ 快捷键说明

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