1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1996,2008 Oracle.  All rights reserved.
5 *
6 * $Id: mp_trickle.c,v 12.20 2008/01/08 20:58:42 bostic Exp $
7 */
8
9#include "db_config.h"
10
11#include "db_int.h"
12#include "dbinc/log.h"
13#include "dbinc/mp.h"
14
15static int __memp_trickle __P((ENV *, int, int *));
16
17/*
18 * __memp_trickle_pp --
19 *	ENV->memp_trickle pre/post processing.
20 *
21 * PUBLIC: int __memp_trickle_pp __P((DB_ENV *, int, int *));
22 */
23int
24__memp_trickle_pp(dbenv, pct, nwrotep)
25	DB_ENV *dbenv;
26	int pct, *nwrotep;
27{
28	DB_THREAD_INFO *ip;
29	ENV *env;
30	int ret;
31
32	env = dbenv->env;
33
34	ENV_REQUIRES_CONFIG(env,
35	    env->mp_handle, "memp_trickle", DB_INIT_MPOOL);
36
37	ENV_ENTER(env, ip);
38	REPLICATION_WRAP(env, (__memp_trickle(env, pct, nwrotep)), 0, ret);
39	ENV_LEAVE(env, ip);
40	return (ret);
41}
42
43/*
44 * __memp_trickle --
45 *	ENV->memp_trickle.
46 */
47static int
48__memp_trickle(env, pct, nwrotep)
49	ENV *env;
50	int pct, *nwrotep;
51{
52	DB_MPOOL *dbmp;
53	MPOOL *c_mp, *mp;
54	u_int32_t clean, dirty, i, need_clean, total, dtmp, wrote;
55	int ret;
56
57	dbmp = env->mp_handle;
58	mp = dbmp->reginfo[0].primary;
59
60	if (nwrotep != NULL)
61		*nwrotep = 0;
62
63	if (pct < 1 || pct > 100) {
64		__db_errx(env,
65	    "DB_ENV->memp_trickle: %d: percent must be between 1 and 100",
66		    pct);
67		return (EINVAL);
68	}
69
70	/*
71	 * Loop through the caches counting total/dirty buffers.
72	 *
73	 * XXX
74	 * Using hash_page_dirty is our only choice at the moment, but it's not
75	 * as correct as we might like in the presence of pools having more
76	 * than one page size, as a free 512B buffer may not be equivalent to
77	 * having a free 8KB buffer.
78	 */
79	for (ret = 0, i = dirty = total = 0; i < mp->nreg; ++i) {
80		c_mp = dbmp->reginfo[i].primary;
81		total += c_mp->stat.st_pages;
82		__memp_stat_hash(&dbmp->reginfo[i], c_mp, &dtmp);
83		dirty += dtmp;
84	}
85
86	/*
87	 * If there are sufficient clean buffers, no buffers or no dirty
88	 * buffers, we're done.
89	 */
90	if (total == 0 || dirty == 0)
91		return (0);
92
93	/*
94	 * The total number of pages is an exact number, but the dirty page
95	 * count can change while we're walking the hash buckets, and it's
96	 * even possible the dirty page count ends up larger than the total
97	 * number of pages.
98	 */
99	clean = total > dirty ? total - dirty : 0;
100	need_clean = (total * (u_int)pct) / 100;
101	if (clean >= need_clean)
102		return (0);
103
104	need_clean -= clean;
105	ret = __memp_sync_int(env, NULL,
106	    need_clean, DB_SYNC_TRICKLE | DB_SYNC_INTERRUPT_OK, &wrote, NULL);
107	STAT((mp->stat.st_page_trickle += wrote));
108	if (nwrotep != NULL)
109		*nwrotep = (int)wrote;
110
111	return (ret);
112}
113