xref: /freebsd/lib/libc/db/mpool/mpool.c (revision 7efabbb915b6ca675726c81d57d254e4d080c3b2)
158f0484fSRodney W. Grimes /*-
2f1e396bcSPaul Traina  * Copyright (c) 1990, 1993, 1994
358f0484fSRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
458f0484fSRodney W. Grimes  *
558f0484fSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
658f0484fSRodney W. Grimes  * modification, are permitted provided that the following conditions
758f0484fSRodney W. Grimes  * are met:
858f0484fSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
958f0484fSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
1058f0484fSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
1158f0484fSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
1258f0484fSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
1358f0484fSRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
1458f0484fSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
1558f0484fSRodney W. Grimes  *    without specific prior written permission.
1658f0484fSRodney W. Grimes  *
1758f0484fSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1858f0484fSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1958f0484fSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2058f0484fSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2158f0484fSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2258f0484fSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2358f0484fSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2458f0484fSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2558f0484fSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2658f0484fSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2758f0484fSRodney W. Grimes  * SUCH DAMAGE.
2858f0484fSRodney W. Grimes  */
2958f0484fSRodney W. Grimes 
3058f0484fSRodney W. Grimes #if defined(LIBC_SCCS) && !defined(lint)
31f1e396bcSPaul Traina static char sccsid[] = "@(#)mpool.c	8.5 (Berkeley) 7/26/94";
3258f0484fSRodney W. Grimes #endif /* LIBC_SCCS and not lint */
33333fc21eSDavid E. O'Brien #include <sys/cdefs.h>
34333fc21eSDavid E. O'Brien __FBSDID("$FreeBSD$");
3558f0484fSRodney W. Grimes 
36d201fe46SDaniel Eischen #include "namespace.h"
3758f0484fSRodney W. Grimes #include <sys/param.h>
38f1e396bcSPaul Traina #include <sys/queue.h>
3958f0484fSRodney W. Grimes #include <sys/stat.h>
4058f0484fSRodney W. Grimes 
4158f0484fSRodney W. Grimes #include <errno.h>
4258f0484fSRodney W. Grimes #include <stdio.h>
4358f0484fSRodney W. Grimes #include <stdlib.h>
4458f0484fSRodney W. Grimes #include <string.h>
4558f0484fSRodney W. Grimes #include <unistd.h>
46d201fe46SDaniel Eischen #include "un-namespace.h"
4758f0484fSRodney W. Grimes 
4858f0484fSRodney W. Grimes #include <db.h>
49f1e396bcSPaul Traina 
5058f0484fSRodney W. Grimes #define	__MPOOLINTERFACE_PRIVATE
51f1e396bcSPaul Traina #include <mpool.h>
5258f0484fSRodney W. Grimes 
53c05ac53bSDavid E. O'Brien static BKT *mpool_bkt(MPOOL *);
54c05ac53bSDavid E. O'Brien static BKT *mpool_look(MPOOL *, pgno_t);
55c05ac53bSDavid E. O'Brien static int  mpool_write(MPOOL *, BKT *);
5658f0484fSRodney W. Grimes 
5758f0484fSRodney W. Grimes /*
58f1e396bcSPaul Traina  * mpool_open --
59f1e396bcSPaul Traina  *	Initialize a memory pool.
6058f0484fSRodney W. Grimes  */
610ac22237SXin LI /* ARGSUSED */
6258f0484fSRodney W. Grimes MPOOL *
630ac22237SXin LI mpool_open(void *key, int fd, pgno_t pagesize, pgno_t maxcache)
6458f0484fSRodney W. Grimes {
6558f0484fSRodney W. Grimes 	struct stat sb;
6658f0484fSRodney W. Grimes 	MPOOL *mp;
6758f0484fSRodney W. Grimes 	int entry;
6858f0484fSRodney W. Grimes 
69f1e396bcSPaul Traina 	/*
70f1e396bcSPaul Traina 	 * Get information about the file.
71f1e396bcSPaul Traina 	 *
72f1e396bcSPaul Traina 	 * XXX
73f1e396bcSPaul Traina 	 * We don't currently handle pipes, although we should.
74f1e396bcSPaul Traina 	 */
75d201fe46SDaniel Eischen 	if (_fstat(fd, &sb))
7658f0484fSRodney W. Grimes 		return (NULL);
7758f0484fSRodney W. Grimes 	if (!S_ISREG(sb.st_mode)) {
7858f0484fSRodney W. Grimes 		errno = ESPIPE;
7958f0484fSRodney W. Grimes 		return (NULL);
8058f0484fSRodney W. Grimes 	}
8158f0484fSRodney W. Grimes 
82f1e396bcSPaul Traina 	/* Allocate and initialize the MPOOL cookie. */
83f1e396bcSPaul Traina 	if ((mp = (MPOOL *)calloc(1, sizeof(MPOOL))) == NULL)
8458f0484fSRodney W. Grimes 		return (NULL);
85fabacd3aSPoul-Henning Kamp 	TAILQ_INIT(&mp->lqh);
8658f0484fSRodney W. Grimes 	for (entry = 0; entry < HASHSIZE; ++entry)
87fabacd3aSPoul-Henning Kamp 		TAILQ_INIT(&mp->hqh[entry]);
8858f0484fSRodney W. Grimes 	mp->maxcache = maxcache;
8958f0484fSRodney W. Grimes 	mp->npages = sb.st_size / pagesize;
90f1e396bcSPaul Traina 	mp->pagesize = pagesize;
9158f0484fSRodney W. Grimes 	mp->fd = fd;
9258f0484fSRodney W. Grimes 	return (mp);
9358f0484fSRodney W. Grimes }
9458f0484fSRodney W. Grimes 
9558f0484fSRodney W. Grimes /*
96f1e396bcSPaul Traina  * mpool_filter --
97f1e396bcSPaul Traina  *	Initialize input/output filters.
9858f0484fSRodney W. Grimes  */
9958f0484fSRodney W. Grimes void
1000ac22237SXin LI mpool_filter(MPOOL *mp, void (*pgin) (void *, pgno_t, void *),
1010ac22237SXin LI     void (*pgout) (void *, pgno_t, void *), void *pgcookie)
10258f0484fSRodney W. Grimes {
10358f0484fSRodney W. Grimes 	mp->pgin = pgin;
10458f0484fSRodney W. Grimes 	mp->pgout = pgout;
10558f0484fSRodney W. Grimes 	mp->pgcookie = pgcookie;
10658f0484fSRodney W. Grimes }
10758f0484fSRodney W. Grimes 
10858f0484fSRodney W. Grimes /*
109f1e396bcSPaul Traina  * mpool_new --
110f1e396bcSPaul Traina  *	Get a new page of memory.
11158f0484fSRodney W. Grimes  */
11258f0484fSRodney W. Grimes void *
11358f0484fSRodney W. Grimes mpool_new(mp, pgnoaddr)
11458f0484fSRodney W. Grimes 	MPOOL *mp;
11558f0484fSRodney W. Grimes 	pgno_t *pgnoaddr;
11658f0484fSRodney W. Grimes {
117f1e396bcSPaul Traina 	struct _hqh *head;
118f1e396bcSPaul Traina 	BKT *bp;
11958f0484fSRodney W. Grimes 
120f1e396bcSPaul Traina 	if (mp->npages == MAX_PAGE_NUMBER) {
121f1e396bcSPaul Traina 		(void)fprintf(stderr, "mpool_new: page allocation overflow.\n");
122f1e396bcSPaul Traina 		abort();
123f1e396bcSPaul Traina 	}
12458f0484fSRodney W. Grimes #ifdef STATISTICS
12558f0484fSRodney W. Grimes 	++mp->pagenew;
12658f0484fSRodney W. Grimes #endif
12758f0484fSRodney W. Grimes 	/*
128f1e396bcSPaul Traina 	 * Get a BKT from the cache.  Assign a new page number, attach
129f1e396bcSPaul Traina 	 * it to the head of the hash chain, the tail of the lru chain,
130f1e396bcSPaul Traina 	 * and return.
13158f0484fSRodney W. Grimes 	 */
132f1e396bcSPaul Traina 	if ((bp = mpool_bkt(mp)) == NULL)
13358f0484fSRodney W. Grimes 		return (NULL);
134f1e396bcSPaul Traina 	*pgnoaddr = bp->pgno = mp->npages++;
135f1e396bcSPaul Traina 	bp->flags = MPOOL_PINNED;
136f1e396bcSPaul Traina 
137f1e396bcSPaul Traina 	head = &mp->hqh[HASHKEY(bp->pgno)];
138fabacd3aSPoul-Henning Kamp 	TAILQ_INSERT_HEAD(head, bp, hq);
139fabacd3aSPoul-Henning Kamp 	TAILQ_INSERT_TAIL(&mp->lqh, bp, q);
140f1e396bcSPaul Traina 	return (bp->page);
14158f0484fSRodney W. Grimes }
14258f0484fSRodney W. Grimes 
14358f0484fSRodney W. Grimes /*
144f1e396bcSPaul Traina  * mpool_get
145f1e396bcSPaul Traina  *	Get a page.
14658f0484fSRodney W. Grimes  */
1470ac22237SXin LI /* ARGSUSED */
14858f0484fSRodney W. Grimes void *
1490ac22237SXin LI mpool_get(MPOOL *mp, pgno_t pgno,
1500ac22237SXin LI     u_int flags)		/* XXX not used? */
15158f0484fSRodney W. Grimes {
152f1e396bcSPaul Traina 	struct _hqh *head;
153f1e396bcSPaul Traina 	BKT *bp;
15458f0484fSRodney W. Grimes 	off_t off;
15558f0484fSRodney W. Grimes 	int nr;
15658f0484fSRodney W. Grimes 
157f1e396bcSPaul Traina 	/* Check for attempt to retrieve a non-existent page. */
15858f0484fSRodney W. Grimes 	if (pgno >= mp->npages) {
15958f0484fSRodney W. Grimes 		errno = EINVAL;
16058f0484fSRodney W. Grimes 		return (NULL);
16158f0484fSRodney W. Grimes 	}
16258f0484fSRodney W. Grimes 
163f1e396bcSPaul Traina #ifdef STATISTICS
164f1e396bcSPaul Traina 	++mp->pageget;
165f1e396bcSPaul Traina #endif
16658f0484fSRodney W. Grimes 
167f1e396bcSPaul Traina 	/* Check for a page that is cached. */
168f1e396bcSPaul Traina 	if ((bp = mpool_look(mp, pgno)) != NULL) {
169f1e396bcSPaul Traina #ifdef DEBUG
170f1e396bcSPaul Traina 		if (bp->flags & MPOOL_PINNED) {
171f1e396bcSPaul Traina 			(void)fprintf(stderr,
172f1e396bcSPaul Traina 			    "mpool_get: page %d already pinned\n", bp->pgno);
173f1e396bcSPaul Traina 			abort();
174f1e396bcSPaul Traina 		}
175f1e396bcSPaul Traina #endif
176f1e396bcSPaul Traina 		/*
177f1e396bcSPaul Traina 		 * Move the page to the head of the hash chain and the tail
178f1e396bcSPaul Traina 		 * of the lru chain.
179f1e396bcSPaul Traina 		 */
180f1e396bcSPaul Traina 		head = &mp->hqh[HASHKEY(bp->pgno)];
181fabacd3aSPoul-Henning Kamp 		TAILQ_REMOVE(head, bp, hq);
182fabacd3aSPoul-Henning Kamp 		TAILQ_INSERT_HEAD(head, bp, hq);
183fabacd3aSPoul-Henning Kamp 		TAILQ_REMOVE(&mp->lqh, bp, q);
184fabacd3aSPoul-Henning Kamp 		TAILQ_INSERT_TAIL(&mp->lqh, bp, q);
185f1e396bcSPaul Traina 
186f1e396bcSPaul Traina 		/* Return a pinned page. */
187f1e396bcSPaul Traina 		bp->flags |= MPOOL_PINNED;
188f1e396bcSPaul Traina 		return (bp->page);
189f1e396bcSPaul Traina 	}
190f1e396bcSPaul Traina 
191f1e396bcSPaul Traina 	/* Get a page from the cache. */
192f1e396bcSPaul Traina 	if ((bp = mpool_bkt(mp)) == NULL)
193f1e396bcSPaul Traina 		return (NULL);
194f1e396bcSPaul Traina 
195f1e396bcSPaul Traina 	/* Read in the contents. */
19658f0484fSRodney W. Grimes #ifdef STATISTICS
19758f0484fSRodney W. Grimes 	++mp->pageread;
19858f0484fSRodney W. Grimes #endif
19958f0484fSRodney W. Grimes 	off = mp->pagesize * pgno;
200f4d14036SDavid Schultz 	nr = pread(mp->fd, bp->page, mp->pagesize, off);
201f4d14036SDavid Schultz 	if (nr != mp->pagesize) {
20258f0484fSRodney W. Grimes 		if (nr >= 0)
20358f0484fSRodney W. Grimes 			errno = EFTYPE;
20458f0484fSRodney W. Grimes 		return (NULL);
20558f0484fSRodney W. Grimes 	}
20658f0484fSRodney W. Grimes 
207f1e396bcSPaul Traina 	/* Set the page number, pin the page. */
208f1e396bcSPaul Traina 	bp->pgno = pgno;
209f1e396bcSPaul Traina 	bp->flags = MPOOL_PINNED;
210f1e396bcSPaul Traina 
211f1e396bcSPaul Traina 	/*
212f1e396bcSPaul Traina 	 * Add the page to the head of the hash chain and the tail
213f1e396bcSPaul Traina 	 * of the lru chain.
214f1e396bcSPaul Traina 	 */
215f1e396bcSPaul Traina 	head = &mp->hqh[HASHKEY(bp->pgno)];
216fabacd3aSPoul-Henning Kamp 	TAILQ_INSERT_HEAD(head, bp, hq);
217fabacd3aSPoul-Henning Kamp 	TAILQ_INSERT_TAIL(&mp->lqh, bp, q);
218f1e396bcSPaul Traina 
219f1e396bcSPaul Traina 	/* Run through the user's filter. */
220f1e396bcSPaul Traina 	if (mp->pgin != NULL)
221f1e396bcSPaul Traina 		(mp->pgin)(mp->pgcookie, bp->pgno, bp->page);
222f1e396bcSPaul Traina 
223f1e396bcSPaul Traina 	return (bp->page);
22458f0484fSRodney W. Grimes }
22558f0484fSRodney W. Grimes 
22658f0484fSRodney W. Grimes /*
227f1e396bcSPaul Traina  * mpool_put
228f1e396bcSPaul Traina  *	Return a page.
22958f0484fSRodney W. Grimes  */
2300ac22237SXin LI /* ARGSUSED */
23158f0484fSRodney W. Grimes int
2320ac22237SXin LI mpool_put(MPOOL *mp, void *page, u_int flags)
23358f0484fSRodney W. Grimes {
234f1e396bcSPaul Traina 	BKT *bp;
23558f0484fSRodney W. Grimes 
23658f0484fSRodney W. Grimes #ifdef STATISTICS
23758f0484fSRodney W. Grimes 	++mp->pageput;
23858f0484fSRodney W. Grimes #endif
239f1e396bcSPaul Traina 	bp = (BKT *)((char *)page - sizeof(BKT));
24058f0484fSRodney W. Grimes #ifdef DEBUG
241f1e396bcSPaul Traina 	if (!(bp->flags & MPOOL_PINNED)) {
242f1e396bcSPaul Traina 		(void)fprintf(stderr,
243f1e396bcSPaul Traina 		    "mpool_put: page %d not pinned\n", bp->pgno);
244f1e396bcSPaul Traina 		abort();
24558f0484fSRodney W. Grimes 	}
24658f0484fSRodney W. Grimes #endif
247f1e396bcSPaul Traina 	bp->flags &= ~MPOOL_PINNED;
248f1e396bcSPaul Traina 	bp->flags |= flags & MPOOL_DIRTY;
24958f0484fSRodney W. Grimes 	return (RET_SUCCESS);
25058f0484fSRodney W. Grimes }
25158f0484fSRodney W. Grimes 
25258f0484fSRodney W. Grimes /*
253f1e396bcSPaul Traina  * mpool_close
254f1e396bcSPaul Traina  *	Close the buffer pool.
25558f0484fSRodney W. Grimes  */
25658f0484fSRodney W. Grimes int
2570ac22237SXin LI mpool_close(MPOOL *mp)
25858f0484fSRodney W. Grimes {
259f1e396bcSPaul Traina 	BKT *bp;
26058f0484fSRodney W. Grimes 
26158f0484fSRodney W. Grimes 	/* Free up any space allocated to the lru pages. */
262429d4912SBrian Feldman 	while (!TAILQ_EMPTY(&mp->lqh)) {
263429d4912SBrian Feldman 		bp = TAILQ_FIRST(&mp->lqh);
264fabacd3aSPoul-Henning Kamp 		TAILQ_REMOVE(&mp->lqh, bp, q);
265f1e396bcSPaul Traina 		free(bp);
26658f0484fSRodney W. Grimes 	}
267f1e396bcSPaul Traina 
268f1e396bcSPaul Traina 	/* Free the MPOOL cookie. */
26958f0484fSRodney W. Grimes 	free(mp);
27058f0484fSRodney W. Grimes 	return (RET_SUCCESS);
27158f0484fSRodney W. Grimes }
27258f0484fSRodney W. Grimes 
27358f0484fSRodney W. Grimes /*
274f1e396bcSPaul Traina  * mpool_sync
275f1e396bcSPaul Traina  *	Sync the pool to disk.
27658f0484fSRodney W. Grimes  */
27758f0484fSRodney W. Grimes int
2780ac22237SXin LI mpool_sync(MPOOL *mp)
27958f0484fSRodney W. Grimes {
280f1e396bcSPaul Traina 	BKT *bp;
28158f0484fSRodney W. Grimes 
282f1e396bcSPaul Traina 	/* Walk the lru chain, flushing any dirty pages to disk. */
283fabacd3aSPoul-Henning Kamp 	TAILQ_FOREACH(bp, &mp->lqh, q)
284f1e396bcSPaul Traina 		if (bp->flags & MPOOL_DIRTY &&
285f1e396bcSPaul Traina 		    mpool_write(mp, bp) == RET_ERROR)
28658f0484fSRodney W. Grimes 			return (RET_ERROR);
287f1e396bcSPaul Traina 
288f1e396bcSPaul Traina 	/* Sync the file descriptor. */
2899233c4d9SJason Evans 	return (_fsync(mp->fd) ? RET_ERROR : RET_SUCCESS);
29058f0484fSRodney W. Grimes }
29158f0484fSRodney W. Grimes 
29258f0484fSRodney W. Grimes /*
293f1e396bcSPaul Traina  * mpool_bkt
294f1e396bcSPaul Traina  *	Get a page from the cache (or create one).
29558f0484fSRodney W. Grimes  */
29658f0484fSRodney W. Grimes static BKT *
2970ac22237SXin LI mpool_bkt(MPOOL *mp)
29858f0484fSRodney W. Grimes {
299f1e396bcSPaul Traina 	struct _hqh *head;
300f1e396bcSPaul Traina 	BKT *bp;
30158f0484fSRodney W. Grimes 
302f1e396bcSPaul Traina 	/* If under the max cached, always create a new page. */
30358f0484fSRodney W. Grimes 	if (mp->curcache < mp->maxcache)
30458f0484fSRodney W. Grimes 		goto new;
30558f0484fSRodney W. Grimes 
30658f0484fSRodney W. Grimes 	/*
307f1e396bcSPaul Traina 	 * If the cache is max'd out, walk the lru list for a buffer we
308f1e396bcSPaul Traina 	 * can flush.  If we find one, write it (if necessary) and take it
309f1e396bcSPaul Traina 	 * off any lists.  If we don't find anything we grow the cache anyway.
31058f0484fSRodney W. Grimes 	 * The cache never shrinks.
31158f0484fSRodney W. Grimes 	 */
312fabacd3aSPoul-Henning Kamp 	TAILQ_FOREACH(bp, &mp->lqh, q)
313f1e396bcSPaul Traina 		if (!(bp->flags & MPOOL_PINNED)) {
314f1e396bcSPaul Traina 			/* Flush if dirty. */
315f1e396bcSPaul Traina 			if (bp->flags & MPOOL_DIRTY &&
316f1e396bcSPaul Traina 			    mpool_write(mp, bp) == RET_ERROR)
31758f0484fSRodney W. Grimes 				return (NULL);
31858f0484fSRodney W. Grimes #ifdef STATISTICS
31958f0484fSRodney W. Grimes 			++mp->pageflush;
32058f0484fSRodney W. Grimes #endif
321f1e396bcSPaul Traina 			/* Remove from the hash and lru queues. */
322f1e396bcSPaul Traina 			head = &mp->hqh[HASHKEY(bp->pgno)];
323fabacd3aSPoul-Henning Kamp 			TAILQ_REMOVE(head, bp, hq);
324fabacd3aSPoul-Henning Kamp 			TAILQ_REMOVE(&mp->lqh, bp, q);
32558f0484fSRodney W. Grimes #ifdef DEBUG
326f1e396bcSPaul Traina 			{ void *spage;
327f1e396bcSPaul Traina 				spage = bp->page;
328f1e396bcSPaul Traina 				memset(bp, 0xff, sizeof(BKT) + mp->pagesize);
329f1e396bcSPaul Traina 				bp->page = spage;
33058f0484fSRodney W. Grimes 			}
33158f0484fSRodney W. Grimes #endif
332f1e396bcSPaul Traina 			return (bp);
33358f0484fSRodney W. Grimes 		}
33458f0484fSRodney W. Grimes 
335f1e396bcSPaul Traina new:	if ((bp = (BKT *)malloc(sizeof(BKT) + mp->pagesize)) == NULL)
33658f0484fSRodney W. Grimes 		return (NULL);
33758f0484fSRodney W. Grimes #ifdef STATISTICS
33858f0484fSRodney W. Grimes 	++mp->pagealloc;
33958f0484fSRodney W. Grimes #endif
340f1e396bcSPaul Traina #if defined(DEBUG) || defined(PURIFY)
341f1e396bcSPaul Traina 	memset(bp, 0xff, sizeof(BKT) + mp->pagesize);
34258f0484fSRodney W. Grimes #endif
343f1e396bcSPaul Traina 	bp->page = (char *)bp + sizeof(BKT);
34458f0484fSRodney W. Grimes 	++mp->curcache;
345f1e396bcSPaul Traina 	return (bp);
34658f0484fSRodney W. Grimes }
34758f0484fSRodney W. Grimes 
34858f0484fSRodney W. Grimes /*
349f1e396bcSPaul Traina  * mpool_write
350f1e396bcSPaul Traina  *	Write a page to disk.
35158f0484fSRodney W. Grimes  */
35258f0484fSRodney W. Grimes static int
3530ac22237SXin LI mpool_write(MPOOL *mp, BKT *bp)
35458f0484fSRodney W. Grimes {
35558f0484fSRodney W. Grimes 	off_t off;
35658f0484fSRodney W. Grimes 
35758f0484fSRodney W. Grimes #ifdef STATISTICS
35858f0484fSRodney W. Grimes 	++mp->pagewrite;
35958f0484fSRodney W. Grimes #endif
360f1e396bcSPaul Traina 
361f1e396bcSPaul Traina 	/* Run through the user's filter. */
362f1e396bcSPaul Traina 	if (mp->pgout)
363f1e396bcSPaul Traina 		(mp->pgout)(mp->pgcookie, bp->pgno, bp->page);
364f1e396bcSPaul Traina 
365f1e396bcSPaul Traina 	off = mp->pagesize * bp->pgno;
366f4d14036SDavid Schultz 	if (pwrite(mp->fd, bp->page, mp->pagesize, off) != mp->pagesize)
36758f0484fSRodney W. Grimes 		return (RET_ERROR);
368f1e396bcSPaul Traina 
369f1e396bcSPaul Traina 	bp->flags &= ~MPOOL_DIRTY;
37058f0484fSRodney W. Grimes 	return (RET_SUCCESS);
37158f0484fSRodney W. Grimes }
37258f0484fSRodney W. Grimes 
37358f0484fSRodney W. Grimes /*
374f1e396bcSPaul Traina  * mpool_look
375f1e396bcSPaul Traina  *	Lookup a page in the cache.
37658f0484fSRodney W. Grimes  */
37758f0484fSRodney W. Grimes static BKT *
3780ac22237SXin LI mpool_look(MPOOL *mp, pgno_t pgno)
37958f0484fSRodney W. Grimes {
380f1e396bcSPaul Traina 	struct _hqh *head;
381f1e396bcSPaul Traina 	BKT *bp;
38258f0484fSRodney W. Grimes 
383f1e396bcSPaul Traina 	head = &mp->hqh[HASHKEY(pgno)];
384fabacd3aSPoul-Henning Kamp 	TAILQ_FOREACH(bp, head, hq)
385f1e396bcSPaul Traina 		if (bp->pgno == pgno) {
38658f0484fSRodney W. Grimes #ifdef STATISTICS
38758f0484fSRodney W. Grimes 			++mp->cachehit;
38858f0484fSRodney W. Grimes #endif
389f1e396bcSPaul Traina 			return (bp);
39058f0484fSRodney W. Grimes 		}
39158f0484fSRodney W. Grimes #ifdef STATISTICS
39258f0484fSRodney W. Grimes 	++mp->cachemiss;
39358f0484fSRodney W. Grimes #endif
39458f0484fSRodney W. Grimes 	return (NULL);
39558f0484fSRodney W. Grimes }
39658f0484fSRodney W. Grimes 
39758f0484fSRodney W. Grimes #ifdef STATISTICS
39858f0484fSRodney W. Grimes /*
399f1e396bcSPaul Traina  * mpool_stat
400f1e396bcSPaul Traina  *	Print out cache statistics.
40158f0484fSRodney W. Grimes  */
40258f0484fSRodney W. Grimes void
4030ac22237SXin LI mpool_stat(MPOOL *mp)
40458f0484fSRodney W. Grimes {
405f1e396bcSPaul Traina 	BKT *bp;
40658f0484fSRodney W. Grimes 	int cnt;
40758f0484fSRodney W. Grimes 	char *sep;
40858f0484fSRodney W. Grimes 
4097efabbb9SXin LI 	(void)fprintf(stderr, "%lu pages in the file\n", mp->npages);
41058f0484fSRodney W. Grimes 	(void)fprintf(stderr,
4117efabbb9SXin LI 	    "page size %lu, cacheing %lu pages of %lu page max cache\n",
41258f0484fSRodney W. Grimes 	    mp->pagesize, mp->curcache, mp->maxcache);
41358f0484fSRodney W. Grimes 	(void)fprintf(stderr, "%lu page puts, %lu page gets, %lu page new\n",
41458f0484fSRodney W. Grimes 	    mp->pageput, mp->pageget, mp->pagenew);
41558f0484fSRodney W. Grimes 	(void)fprintf(stderr, "%lu page allocs, %lu page flushes\n",
41658f0484fSRodney W. Grimes 	    mp->pagealloc, mp->pageflush);
41758f0484fSRodney W. Grimes 	if (mp->cachehit + mp->cachemiss)
41858f0484fSRodney W. Grimes 		(void)fprintf(stderr,
41958f0484fSRodney W. Grimes 		    "%.0f%% cache hit rate (%lu hits, %lu misses)\n",
42058f0484fSRodney W. Grimes 		    ((double)mp->cachehit / (mp->cachehit + mp->cachemiss))
42158f0484fSRodney W. Grimes 		    * 100, mp->cachehit, mp->cachemiss);
42258f0484fSRodney W. Grimes 	(void)fprintf(stderr, "%lu page reads, %lu page writes\n",
42358f0484fSRodney W. Grimes 	    mp->pageread, mp->pagewrite);
42458f0484fSRodney W. Grimes 
42558f0484fSRodney W. Grimes 	sep = "";
42658f0484fSRodney W. Grimes 	cnt = 0;
427fabacd3aSPoul-Henning Kamp 	TAILQ_FOREACH(bp, &mp->lqh, q) {
428f1e396bcSPaul Traina 		(void)fprintf(stderr, "%s%d", sep, bp->pgno);
429f1e396bcSPaul Traina 		if (bp->flags & MPOOL_DIRTY)
43058f0484fSRodney W. Grimes 			(void)fprintf(stderr, "d");
431f1e396bcSPaul Traina 		if (bp->flags & MPOOL_PINNED)
43258f0484fSRodney W. Grimes 			(void)fprintf(stderr, "P");
43358f0484fSRodney W. Grimes 		if (++cnt == 10) {
43458f0484fSRodney W. Grimes 			sep = "\n";
43558f0484fSRodney W. Grimes 			cnt = 0;
43658f0484fSRodney W. Grimes 		} else
43758f0484fSRodney W. Grimes 			sep = ", ";
43858f0484fSRodney W. Grimes 
43958f0484fSRodney W. Grimes 	}
44058f0484fSRodney W. Grimes 	(void)fprintf(stderr, "\n");
44158f0484fSRodney W. Grimes }
44258f0484fSRodney W. Grimes #endif
443