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

📄 mp_fget.c

📁 这是linux下运行的mysql软件包,可用于linux 下安装 php + mysql + apach 的网络配置
💻 C
📖 第 1 页 / 共 2 页
字号:
/*- * See the file LICENSE for redistribution information. * * Copyright (c) 1996-2002 *	Sleepycat Software.  All rights reserved. */#include "db_config.h"#ifndef lintstatic const char revid[] = "$Id: mp_fget.c,v 11.68 2002/08/06 04:58:09 bostic Exp $";#endif /* not lint */#ifndef NO_SYSTEM_INCLUDES#include <sys/types.h>#include <string.h>#endif#include "db_int.h"#include "dbinc/db_shash.h"#include "dbinc/mp.h"#ifdef HAVE_FILESYSTEM_NOTZEROstatic int __memp_fs_notzero    __P((DB_ENV *, DB_MPOOLFILE *, MPOOLFILE *, db_pgno_t *));#endif/* * __memp_fget -- *	Get a page from the file. * * PUBLIC: int __memp_fget * PUBLIC:     __P((DB_MPOOLFILE *, db_pgno_t *, u_int32_t, void *)); */int__memp_fget(dbmfp, pgnoaddr, flags, addrp)	DB_MPOOLFILE *dbmfp;	db_pgno_t *pgnoaddr;	u_int32_t flags;	void *addrp;{	enum { FIRST_FOUND, FIRST_MISS, SECOND_FOUND, SECOND_MISS } state;	BH *alloc_bhp, *bhp;	DB_ENV *dbenv;	DB_MPOOL *dbmp;	DB_MPOOL_HASH *hp;	MPOOL *c_mp, *mp;	MPOOLFILE *mfp;	roff_t mf_offset;	u_int32_t n_cache, st_hsearch;	int b_incr, extending, first, ret;	*(void **)addrp = NULL;	dbmp = dbmfp->dbmp;	dbenv = dbmp->dbenv;	PANIC_CHECK(dbenv);	mp = dbmp->reginfo[0].primary;	mfp = dbmfp->mfp;	mf_offset = R_OFFSET(dbmp->reginfo, mfp);	alloc_bhp = bhp = NULL;	hp = NULL;	b_incr = extending = ret = 0;	/*	 * Validate arguments.	 *	 * !!!	 * Don't test for DB_MPOOL_CREATE and DB_MPOOL_NEW flags for readonly	 * files here, and create non-existent pages in readonly files if the	 * flags are set, later.  The reason is that the hash access method	 * wants to get empty pages that don't really exist in readonly files.	 * The only alternative is for hash to write the last "bucket" all the	 * time, which we don't want to do because one of our big goals in life	 * is to keep database files small.  It's sleazy as hell, but we catch	 * any attempt to actually write the file in memp_fput().	 */#define	OKFLAGS		(DB_MPOOL_CREATE | DB_MPOOL_LAST | DB_MPOOL_NEW)	if (flags != 0) {		if ((ret = __db_fchk(dbenv, "memp_fget", flags, OKFLAGS)) != 0)			return (ret);		switch (flags) {		case DB_MPOOL_CREATE:			break;		case DB_MPOOL_LAST:			/* Get the last page number in the file. */			if (flags == DB_MPOOL_LAST) {				R_LOCK(dbenv, dbmp->reginfo);				*pgnoaddr = mfp->last_pgno;				R_UNLOCK(dbenv, dbmp->reginfo);			}			break;		case DB_MPOOL_NEW:			/*			 * If always creating a page, skip the first search			 * of the hash bucket.			 */			if (flags == DB_MPOOL_NEW)				goto alloc;			break;		default:			return (__db_ferr(dbenv, "memp_fget", 1));		}	}	/*	 * If mmap'ing the file and the page is not past the end of the file,	 * just return a pointer.	 *	 * The page may be past the end of the file, so check the page number	 * argument against the original length of the file.  If we previously	 * returned pages past the original end of the file, last_pgno will	 * have been updated to match the "new" end of the file, and checking	 * against it would return pointers past the end of the mmap'd region.	 *	 * If another process has opened the file for writing since we mmap'd	 * it, we will start playing the game by their rules, i.e. everything	 * goes through the cache.  All pages previously returned will be safe,	 * as long as the correct locking protocol was observed.	 *	 * We don't discard the map because we don't know when all of the	 * pages will have been discarded from the process' address space.	 * It would be possible to do so by reference counting the open	 * pages from the mmap, but it's unclear to me that it's worth it.	 */	if (dbmfp->addr != NULL &&	    F_ISSET(mfp, MP_CAN_MMAP) && *pgnoaddr <= mfp->orig_last_pgno) {		*(void **)addrp =		    R_ADDR(dbmfp, *pgnoaddr * mfp->stat.st_pagesize);		++mfp->stat.st_map;		return (0);	}hb_search:	/*	 * Determine the cache and hash bucket where this page lives and get	 * local pointers to them.  Reset on each pass through this code, the	 * page number can change.	 */	n_cache = NCACHE(mp, mf_offset, *pgnoaddr);	c_mp = dbmp->reginfo[n_cache].primary;	hp = R_ADDR(&dbmp->reginfo[n_cache], c_mp->htab);	hp = &hp[NBUCKET(c_mp, mf_offset, *pgnoaddr)];	/* Search the hash chain for the page. */retry:	st_hsearch = 0;	MUTEX_LOCK(dbenv, &hp->hash_mutex);	for (bhp = SH_TAILQ_FIRST(&hp->hash_bucket, __bh);	    bhp != NULL; bhp = SH_TAILQ_NEXT(bhp, hq, __bh)) {		++st_hsearch;		if (bhp->pgno != *pgnoaddr || bhp->mf_offset != mf_offset)			continue;		/*		 * Increment the reference count.  We may discard the hash		 * bucket lock as we evaluate and/or read the buffer, so we		 * need to ensure it doesn't move and its contents remain		 * unchanged.		 */		if (bhp->ref == UINT16_T_MAX) {			__db_err(dbenv,			    "%s: page %lu: reference count overflow",			    __memp_fn(dbmfp), (u_long)bhp->pgno);			ret = EINVAL;			MUTEX_UNLOCK(dbenv, &hp->hash_mutex);			goto err;		}		++bhp->ref;		b_incr = 1;		/*		 * BH_LOCKED --		 * I/O is in progress or sync is waiting on the buffer to write		 * it.  Because we've incremented the buffer reference count,		 * we know the buffer can't move.  Unlock the bucket lock, wait		 * for the buffer to become available, reacquire the bucket.		 */		for (first = 1; F_ISSET(bhp, BH_LOCKED) &&		    !F_ISSET(dbenv, DB_ENV_NOLOCKING); first = 0) {			/*			 * If someone is trying to sync this buffer and the			 * buffer is hot, they may never get in.  Give up			 * and try again.			 */			if (!first && bhp->ref_sync != 0) {				--bhp->ref;				b_incr = 0;				MUTEX_UNLOCK(dbenv, &hp->hash_mutex);				__os_yield(dbenv, 1);				goto retry;			}			MUTEX_UNLOCK(dbenv, &hp->hash_mutex);			/*			 * Explicitly yield the processor if not the first pass			 * through this loop -- if we don't, we might run to the			 * end of our CPU quantum as we will simply be swapping			 * between the two locks.			 */			if (!first)				__os_yield(dbenv, 1);			MUTEX_LOCK(dbenv, &bhp->mutex);			/* Wait for I/O to finish... */			MUTEX_UNLOCK(dbenv, &bhp->mutex);			MUTEX_LOCK(dbenv, &hp->hash_mutex);		}		++mfp->stat.st_cache_hit;		break;	}	/*	 * Update the hash bucket search statistics -- do now because our next	 * search may be for a different bucket.	 */	++c_mp->stat.st_hash_searches;	if (st_hsearch > c_mp->stat.st_hash_longest)		c_mp->stat.st_hash_longest = st_hsearch;	c_mp->stat.st_hash_examined += st_hsearch;	/*	 * There are 4 possible paths to this location:	 *	 * FIRST_MISS:	 *	Didn't find the page in the hash bucket on our first pass:	 *	bhp == NULL, alloc_bhp == NULL	 *	 * FIRST_FOUND:	 *	Found the page in the hash bucket on our first pass:	 *	bhp != NULL, alloc_bhp == NULL	 *	 * SECOND_FOUND:	 *	Didn't find the page in the hash bucket on the first pass,	 *	allocated space, and found the page in the hash bucket on	 *	our second pass:	 *	bhp != NULL, alloc_bhp != NULL	 *	 * SECOND_MISS:	 *	Didn't find the page in the hash bucket on the first pass,	 *	allocated space, and didn't find the page in the hash bucket	 *	on our second pass:	 *	bhp == NULL, alloc_bhp != NULL	 */	state = bhp == NULL ?	    (alloc_bhp == NULL ? FIRST_MISS : SECOND_MISS) :	    (alloc_bhp == NULL ? FIRST_FOUND : SECOND_FOUND);	switch (state) {	case FIRST_FOUND:		/* We found the buffer in our first check -- we're done. */		break;	case FIRST_MISS:		/*		 * We didn't find the buffer in our first check.  Figure out		 * if the page exists, and allocate structures so we can add		 * the page to the buffer pool.		 */		MUTEX_UNLOCK(dbenv, &hp->hash_mutex);alloc:		/*		 * If DB_MPOOL_NEW is set, we have to allocate a page number.		 * If neither DB_MPOOL_CREATE or DB_MPOOL_CREATE is set, then		 * it's an error to try and get a page past the end of file.		 */		COMPQUIET(n_cache, 0);		extending = ret = 0;		R_LOCK(dbenv, dbmp->reginfo);		switch (flags) {		case DB_MPOOL_NEW:			extending = 1;			*pgnoaddr = mfp->last_pgno + 1;			break;		case DB_MPOOL_CREATE:			extending = *pgnoaddr > mfp->last_pgno;			break;		default:			ret = *pgnoaddr > mfp->last_pgno ? DB_PAGE_NOTFOUND : 0;			break;		}		R_UNLOCK(dbenv, dbmp->reginfo);		if (ret != 0)			goto err;		/*		 * !!!		 * In the DB_MPOOL_NEW code path, mf_offset and n_cache have		 * not yet been initialized.		 */		mf_offset = R_OFFSET(dbmp->reginfo, mfp);		n_cache = NCACHE(mp, mf_offset, *pgnoaddr);		/* Allocate a new buffer header and data space. */		if ((ret = __memp_alloc(dbmp,		    &dbmp->reginfo[n_cache], mfp, 0, NULL, &alloc_bhp)) != 0)			goto err;#ifdef DIAGNOSTIC		if ((db_alignp_t)alloc_bhp->buf & (sizeof(size_t) - 1)) {			__db_err(dbenv,			    "Error: buffer data is NOT size_t aligned");			ret = EINVAL;			goto err;		}#endif		/*		 * If we are extending the file, we'll need the region lock		 * again.		 */		if (extending)			R_LOCK(dbenv, dbmp->reginfo);		/*		 * DB_MPOOL_NEW does not guarantee you a page unreferenced by		 * any other thread of control.  (That guarantee is interesting		 * for DB_MPOOL_NEW, unlike DB_MPOOL_CREATE, because the caller		 * did not specify the page number, and so, may reasonably not		 * have any way to lock the page outside of mpool.) Regardless,		 * if we allocate the page, and some other thread of control		 * requests the page by number, we will not detect that and the		 * thread of control that allocated using DB_MPOOL_NEW may not		 * have a chance to initialize the page.  (Note: we *could*		 * detect this case if we set a flag in the buffer header which		 * guaranteed that no gets of the page would succeed until the		 * reference count went to 0, that is, until the creating page		 * put the page.)  What we do guarantee is that if two threads

⌨️ 快捷键说明

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