You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
155 lines
3.8 KiB
155 lines
3.8 KiB
/*-
|
|
* See the file LICENSE for redistribution information.
|
|
*
|
|
* Copyright (c) 1996, 1997, 1998, 1999
|
|
* Sleepycat Software. All rights reserved.
|
|
*/
|
|
#include "db_config.h"
|
|
|
|
#ifndef lint
|
|
static const char sccsid[] = "@(#)mp_alloc.c 11.3 (Sleepycat) 9/29/99";
|
|
#endif /* not lint */
|
|
|
|
#ifndef NO_SYSTEM_INCLUDES
|
|
#include <sys/types.h>
|
|
#endif
|
|
|
|
#include "db_int.h"
|
|
#include "db_shash.h"
|
|
#include "mp.h"
|
|
|
|
/*
|
|
* CDB___memp_alloc --
|
|
* Allocate some space in the mpool region.
|
|
*
|
|
* PUBLIC: int CDB___memp_alloc __P((DB_MPOOL *,
|
|
* PUBLIC: REGINFO *, MPOOLFILE *, size_t, roff_t *, void *));
|
|
*/
|
|
int
|
|
CDB___memp_alloc(dbmp, memreg, mfp, len, offsetp, retp)
|
|
DB_MPOOL *dbmp;
|
|
REGINFO *memreg;
|
|
MPOOLFILE *mfp;
|
|
size_t len;
|
|
roff_t *offsetp;
|
|
void *retp;
|
|
{
|
|
BH *bhp, *nbhp;
|
|
MCACHE *mc;
|
|
MPOOL *mp;
|
|
MPOOLFILE *bh_mfp;
|
|
size_t total;
|
|
int nomore, restart, ret, wrote;
|
|
void *p;
|
|
|
|
mp = dbmp->reginfo.primary;
|
|
mc = memreg->primary;
|
|
|
|
/*
|
|
* If we're allocating a buffer, and the one we're discarding is the
|
|
* same size, we don't want to waste the time to re-integrate it into
|
|
* the shared memory free list. If the DB_MPOOLFILE argument isn't
|
|
* NULL, we'll compare the underlying page sizes of the two buffers
|
|
* before free-ing and re-allocating buffers.
|
|
*/
|
|
if (mfp != NULL)
|
|
len = (sizeof(BH) - sizeof(u_int8_t)) + mfp->stat.st_pagesize;
|
|
|
|
nomore = 0;
|
|
alloc: if ((ret = CDB___db_shalloc(memreg->addr, len, MUTEX_ALIGN, &p)) == 0) {
|
|
if (offsetp != NULL)
|
|
*offsetp = R_OFFSET(memreg, p);
|
|
*(void **)retp = p;
|
|
return (0);
|
|
}
|
|
if (nomore) {
|
|
CDB___db_err(dbmp->dbenv,
|
|
"Unable to allocate %lu bytes from mpool shared region: %s\n",
|
|
(u_long)len, CDB_db_strerror(ret));
|
|
return (ret);
|
|
}
|
|
|
|
retry: /* Find a buffer we can flush; pure LRU. */
|
|
restart = total = 0;
|
|
for (bhp =
|
|
SH_TAILQ_FIRST(&mc->bhq, __bh); bhp != NULL; bhp = nbhp) {
|
|
nbhp = SH_TAILQ_NEXT(bhp, q, __bh);
|
|
|
|
/* Ignore pinned or locked (I/O in progress) buffers. */
|
|
if (bhp->ref != 0 || F_ISSET(bhp, BH_LOCKED))
|
|
continue;
|
|
|
|
/* Find the associated MPOOLFILE. */
|
|
bh_mfp = R_ADDR(&dbmp->reginfo, bhp->mf_offset);
|
|
|
|
/* Write the page if it's dirty. */
|
|
if (F_ISSET(bhp, BH_DIRTY)) {
|
|
++bhp->ref;
|
|
if ((ret = CDB___memp_bhwrite(dbmp,
|
|
bh_mfp, bhp, &restart, &wrote)) != 0)
|
|
return (ret);
|
|
--bhp->ref;
|
|
|
|
/*
|
|
* Another process may have acquired this buffer and
|
|
* incremented the ref count after we wrote it.
|
|
*/
|
|
if (bhp->ref != 0)
|
|
goto retry;
|
|
|
|
/*
|
|
* If we wrote the page, continue and free the buffer.
|
|
* We don't have to rewalk the list to acquire the
|
|
* buffer because it was never available for any other
|
|
* process to modify it.
|
|
*
|
|
* If we didn't write the page, but we discarded and
|
|
* reacquired the region lock, restart the list walk.
|
|
*
|
|
* If we neither wrote the buffer nor discarded the
|
|
* region lock, continue down the buffer list.
|
|
*/
|
|
if (wrote)
|
|
++mc->stat.st_rw_evict;
|
|
else {
|
|
if (restart)
|
|
goto retry;
|
|
continue;
|
|
}
|
|
} else
|
|
++mc->stat.st_ro_evict;
|
|
|
|
/*
|
|
* Check to see if the buffer is the size we're looking for.
|
|
* If it is, simply reuse it.
|
|
*/
|
|
if (mfp != NULL &&
|
|
mfp->stat.st_pagesize == bh_mfp->stat.st_pagesize) {
|
|
CDB___memp_bhfree(dbmp, bhp, 0);
|
|
|
|
if (offsetp != NULL)
|
|
*offsetp = R_OFFSET(memreg, bhp);
|
|
*(void **)retp = bhp;
|
|
return (0);
|
|
}
|
|
|
|
/* Note how much space we've freed, and free the buffer. */
|
|
total += CDB___db_shsizeof(bhp);
|
|
CDB___memp_bhfree(dbmp, bhp, 1);
|
|
|
|
/*
|
|
* Retry as soon as we've freed up sufficient space. If we
|
|
* have to coalesce of memory to satisfy the request, don't
|
|
* try until it's likely (possible?) that we'll succeed.
|
|
*/
|
|
if (total >= 3 * len)
|
|
goto alloc;
|
|
|
|
/* Restart the walk if we discarded the region lock. */
|
|
if (restart)
|
|
goto retry;
|
|
}
|
|
nomore = 1;
|
|
goto alloc;
|
|
}
|