1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
|
/*-
* 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_trickle.c 11.3 (Sleepycat) 9/16/99";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
#include <errno.h>
#include <stdlib.h>
#endif
#include "db_int.h"
#include "db_shash.h"
#include "mp.h"
static int CDB___memp_trick __P((DB_ENV *, int, int, int *));
/*
* CDB_memp_trickle --
* Keep a specified percentage of the buffers clean.
*/
int
CDB_memp_trickle(dbenv, pct, nwrotep)
DB_ENV *dbenv;
int pct, *nwrotep;
{
DB_MPOOL *dbmp;
MPOOL *mp;
u_int32_t i;
int ret;
PANIC_CHECK(dbenv);
ENV_REQUIRES_CONFIG(dbenv, dbenv->mp_handle, DB_INIT_MPOOL);
dbmp = dbenv->mp_handle;
mp = dbmp->reginfo.primary;
if (nwrotep != NULL)
*nwrotep = 0;
if (pct < 1 || pct > 100)
return (EINVAL);
R_LOCK(dbenv, &dbmp->reginfo);
/* Loop through the caches... */
for (ret = 0, i = 0; i < mp->nc_reg; ++i)
if ((ret = CDB___memp_trick(dbenv, i, pct, nwrotep)) != 0)
break;
R_UNLOCK(dbenv, &dbmp->reginfo);
return (ret);
}
/*
* CDB___memp_trick --
* Trickle a single cache.
*/
static int
CDB___memp_trick(dbenv, ncache, pct, nwrotep)
DB_ENV *dbenv;
int ncache, pct, *nwrotep;
{
BH *bhp;
DB_MPOOL *dbmp;
MCACHE *mc;
MPOOLFILE *mfp;
db_pgno_t pgno;
u_long total;
int ret, wrote;
dbmp = dbenv->mp_handle;
mc = dbmp->c_reginfo[ncache].primary;
/*
* If there are sufficient clean buffers, or no buffers or no dirty
* buffers, we're done.
*
* XXX
* Using st_page_clean and st_page_dirty is our only choice at the
* moment, but it's not as correct as we might like in the presence
* of pools with more than one buffer size, as a free 512-byte buffer
* isn't the same as a free 8K buffer.
*/
loop: total = mc->stat.st_page_clean + mc->stat.st_page_dirty;
if (total == 0 || mc->stat.st_page_dirty == 0 ||
(mc->stat.st_page_clean * 100) / total >= (u_long)pct)
return (0);
/* Loop until we write a buffer. */
for (bhp = SH_TAILQ_FIRST(&mc->bhq, __bh);
bhp != NULL; bhp = SH_TAILQ_NEXT(bhp, q, __bh)) {
if (bhp->ref != 0 ||
!F_ISSET(bhp, BH_DIRTY) || F_ISSET(bhp, BH_LOCKED))
continue;
mfp = R_ADDR(&dbmp->reginfo, bhp->mf_offset);
/*
* We can't write to temporary files -- see the comment in
* mp_bh.c:CDB___memp_bhwrite().
*/
if (F_ISSET(mfp, MP_TEMP))
continue;
pgno = bhp->pgno;
if ((ret = CDB___memp_bhwrite(dbmp, mfp, bhp, NULL, &wrote)) != 0)
return (ret);
/*
* Any process syncing the shared memory buffer pool had better
* be able to write to any underlying file. Be understanding,
* but firm, on this point.
*/
if (!wrote) {
CDB___db_err(dbenv, "%s: unable to flush page: %lu",
CDB___memp_fns(dbmp, mfp), (u_long)pgno);
return (EPERM);
}
++mc->stat.st_page_trickle;
if (nwrotep != NULL)
++*nwrotep;
goto loop;
}
return (0);
}
|