xref: /minix3/lib/libc/db/mpool/mpool.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: mpool.c,v 1.21 2013/12/14 18:04:00 christos Exp $	*/
22639ae9bSBen Gras 
32639ae9bSBen Gras /*-
42639ae9bSBen Gras  * Copyright (c) 1990, 1993, 1994
52639ae9bSBen Gras  *	The Regents of the University of California.  All rights reserved.
62639ae9bSBen Gras  *
72639ae9bSBen Gras  * Redistribution and use in source and binary forms, with or without
82639ae9bSBen Gras  * modification, are permitted provided that the following conditions
92639ae9bSBen Gras  * are met:
102639ae9bSBen Gras  * 1. Redistributions of source code must retain the above copyright
112639ae9bSBen Gras  *    notice, this list of conditions and the following disclaimer.
122639ae9bSBen Gras  * 2. Redistributions in binary form must reproduce the above copyright
132639ae9bSBen Gras  *    notice, this list of conditions and the following disclaimer in the
142639ae9bSBen Gras  *    documentation and/or other materials provided with the distribution.
152639ae9bSBen Gras  * 3. Neither the name of the University nor the names of its contributors
162639ae9bSBen Gras  *    may be used to endorse or promote products derived from this software
172639ae9bSBen Gras  *    without specific prior written permission.
182639ae9bSBen Gras  *
192639ae9bSBen Gras  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
202639ae9bSBen Gras  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
212639ae9bSBen Gras  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
222639ae9bSBen Gras  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
232639ae9bSBen Gras  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
242639ae9bSBen Gras  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
252639ae9bSBen Gras  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
262639ae9bSBen Gras  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
272639ae9bSBen Gras  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
282639ae9bSBen Gras  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
292639ae9bSBen Gras  * SUCH DAMAGE.
302639ae9bSBen Gras  */
312639ae9bSBen Gras 
322639ae9bSBen Gras #if HAVE_NBTOOL_CONFIG_H
332639ae9bSBen Gras #include "nbtool_config.h"
342639ae9bSBen Gras #endif
352639ae9bSBen Gras 
362639ae9bSBen Gras #include <sys/cdefs.h>
37*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: mpool.c,v 1.21 2013/12/14 18:04:00 christos Exp $");
382639ae9bSBen Gras 
392639ae9bSBen Gras #include "namespace.h"
402639ae9bSBen Gras #include <sys/queue.h>
412639ae9bSBen Gras #include <sys/stat.h>
422639ae9bSBen Gras 
432639ae9bSBen Gras #include <errno.h>
442639ae9bSBen Gras #include <stdio.h>
452639ae9bSBen Gras #include <stdlib.h>
462639ae9bSBen Gras #include <string.h>
472639ae9bSBen Gras #include <unistd.h>
482639ae9bSBen Gras 
492639ae9bSBen Gras #include <db.h>
502639ae9bSBen Gras 
512639ae9bSBen Gras #define	__MPOOLINTERFACE_PRIVATE
522639ae9bSBen Gras #include <mpool.h>
532639ae9bSBen Gras 
542639ae9bSBen Gras #ifdef __weak_alias
552639ae9bSBen Gras __weak_alias(mpool_close,_mpool_close)
562639ae9bSBen Gras __weak_alias(mpool_filter,_mpool_filter)
572639ae9bSBen Gras __weak_alias(mpool_get,_mpool_get)
582639ae9bSBen Gras __weak_alias(mpool_new,_mpool_new)
592639ae9bSBen Gras __weak_alias(mpool_open,_mpool_open)
602639ae9bSBen Gras __weak_alias(mpool_put,_mpool_put)
612639ae9bSBen Gras __weak_alias(mpool_sync,_mpool_sync)
622639ae9bSBen Gras #endif
632639ae9bSBen Gras 
642639ae9bSBen Gras static BKT *mpool_bkt(MPOOL *);
652639ae9bSBen Gras static BKT *mpool_look(MPOOL *, pgno_t);
662639ae9bSBen Gras static int  mpool_write(MPOOL *, BKT *);
672639ae9bSBen Gras 
682639ae9bSBen Gras /*
692639ae9bSBen Gras  * mpool_open --
702639ae9bSBen Gras  *	Initialize a memory pool.
712639ae9bSBen Gras  */
722639ae9bSBen Gras /*ARGSUSED*/
732639ae9bSBen Gras MPOOL *
mpool_open(void * key,int fd,pgno_t pagesize,pgno_t maxcache)742639ae9bSBen Gras mpool_open(void *key, int fd, pgno_t pagesize, pgno_t maxcache)
752639ae9bSBen Gras {
762639ae9bSBen Gras 	struct stat sb;
772639ae9bSBen Gras 	MPOOL *mp;
782639ae9bSBen Gras 	int entry;
792639ae9bSBen Gras 
802639ae9bSBen Gras 	/*
812639ae9bSBen Gras 	 * Get information about the file.
822639ae9bSBen Gras 	 *
832639ae9bSBen Gras 	 * XXX
842639ae9bSBen Gras 	 * We don't currently handle pipes, although we should.
852639ae9bSBen Gras 	 */
862639ae9bSBen Gras 	if (fstat(fd, &sb))
87*0a6a1f1dSLionel Sambuc 		return NULL;
882639ae9bSBen Gras 	if (!S_ISREG(sb.st_mode)) {
892639ae9bSBen Gras 		errno = ESPIPE;
90*0a6a1f1dSLionel Sambuc 		return NULL;
912639ae9bSBen Gras 	}
922639ae9bSBen Gras 
932639ae9bSBen Gras 	/* Allocate and initialize the MPOOL cookie. */
94*0a6a1f1dSLionel Sambuc 	if ((mp = calloc(1, sizeof(*mp))) == NULL)
952639ae9bSBen Gras 		return (NULL);
9684d9c625SLionel Sambuc 	TAILQ_INIT(&mp->lqh);
972639ae9bSBen Gras 	for (entry = 0; entry < HASHSIZE; ++entry)
9884d9c625SLionel Sambuc 		TAILQ_INIT(&mp->hqh[entry]);
992639ae9bSBen Gras 	mp->maxcache = maxcache;
1002639ae9bSBen Gras 	mp->npages = (pgno_t)(sb.st_size / pagesize);
1012639ae9bSBen Gras 	mp->pagesize = pagesize;
1022639ae9bSBen Gras 	mp->fd = fd;
103*0a6a1f1dSLionel Sambuc 	return mp;
1042639ae9bSBen Gras }
1052639ae9bSBen Gras 
1062639ae9bSBen Gras /*
1072639ae9bSBen Gras  * mpool_filter --
1082639ae9bSBen Gras  *	Initialize input/output filters.
1092639ae9bSBen Gras  */
1102639ae9bSBen Gras void
mpool_filter(MPOOL * mp,void (* pgin)(void *,pgno_t,void *),void (* pgout)(void *,pgno_t,void *),void * pgcookie)1112639ae9bSBen Gras mpool_filter(MPOOL *mp, void (*pgin)(void *, pgno_t, void *),
1122639ae9bSBen Gras     void (*pgout)(void *, pgno_t, void *), void *pgcookie)
1132639ae9bSBen Gras {
1142639ae9bSBen Gras 	mp->pgin = pgin;
1152639ae9bSBen Gras 	mp->pgout = pgout;
1162639ae9bSBen Gras 	mp->pgcookie = pgcookie;
1172639ae9bSBen Gras }
1182639ae9bSBen Gras 
1192639ae9bSBen Gras /*
1202639ae9bSBen Gras  * mpool_new --
1212639ae9bSBen Gras  *	Get a new page of memory.
1222639ae9bSBen Gras  */
1232639ae9bSBen Gras void *
mpool_new(MPOOL * mp,pgno_t * pgnoaddr)1242639ae9bSBen Gras mpool_new( MPOOL *mp, pgno_t *pgnoaddr)
1252639ae9bSBen Gras {
1262639ae9bSBen Gras 	struct _hqh *head;
1272639ae9bSBen Gras 	BKT *bp;
1282639ae9bSBen Gras 
1292639ae9bSBen Gras 	if (mp->npages == MAX_PAGE_NUMBER) {
1302639ae9bSBen Gras 		(void)fprintf(stderr, "mpool_new: page allocation overflow.\n");
1312639ae9bSBen Gras 		abort();
1322639ae9bSBen Gras 	}
1332639ae9bSBen Gras #ifdef STATISTICS
1342639ae9bSBen Gras 	++mp->pagenew;
1352639ae9bSBen Gras #endif
1362639ae9bSBen Gras 	/*
1372639ae9bSBen Gras 	 * Get a BKT from the cache.  Assign a new page number, attach
1382639ae9bSBen Gras 	 * it to the head of the hash chain, the tail of the lru chain,
1392639ae9bSBen Gras 	 * and return.
1402639ae9bSBen Gras 	 */
1412639ae9bSBen Gras 	if ((bp = mpool_bkt(mp)) == NULL)
142*0a6a1f1dSLionel Sambuc 		return NULL;
1432639ae9bSBen Gras 	*pgnoaddr = bp->pgno = mp->npages++;
1442639ae9bSBen Gras 	bp->flags = MPOOL_PINNED;
1452639ae9bSBen Gras 
1462639ae9bSBen Gras 	head = &mp->hqh[HASHKEY(bp->pgno)];
14784d9c625SLionel Sambuc 	TAILQ_INSERT_HEAD(head, bp, hq);
14884d9c625SLionel Sambuc 	TAILQ_INSERT_TAIL(&mp->lqh, bp, q);
149*0a6a1f1dSLionel Sambuc 	return bp->page;
1502639ae9bSBen Gras }
1512639ae9bSBen Gras 
1522639ae9bSBen Gras /*
1532639ae9bSBen Gras  * mpool_get
1542639ae9bSBen Gras  *	Get a page.
1552639ae9bSBen Gras  */
1562639ae9bSBen Gras /*ARGSUSED*/
1572639ae9bSBen Gras void *
mpool_get(MPOOL * mp,pgno_t pgno,u_int flags)1582639ae9bSBen Gras mpool_get(MPOOL *mp, pgno_t pgno, u_int flags)
1592639ae9bSBen Gras {
1602639ae9bSBen Gras 	struct _hqh *head;
1612639ae9bSBen Gras 	BKT *bp;
1622639ae9bSBen Gras 	off_t off;
1632639ae9bSBen Gras 	ssize_t nr;
1642639ae9bSBen Gras 
1652639ae9bSBen Gras 	/* Check for attempt to retrieve a non-existent page. */
1662639ae9bSBen Gras 	if (pgno >= mp->npages) {
1672639ae9bSBen Gras 		errno = EINVAL;
168*0a6a1f1dSLionel Sambuc 		return NULL;
1692639ae9bSBen Gras 	}
1702639ae9bSBen Gras 
1712639ae9bSBen Gras #ifdef STATISTICS
1722639ae9bSBen Gras 	++mp->pageget;
1732639ae9bSBen Gras #endif
1742639ae9bSBen Gras 
1752639ae9bSBen Gras 	/* Check for a page that is cached. */
1762639ae9bSBen Gras 	if ((bp = mpool_look(mp, pgno)) != NULL) {
1772639ae9bSBen Gras #ifdef DEBUG
1782639ae9bSBen Gras 		if (bp->flags & MPOOL_PINNED) {
1792639ae9bSBen Gras 			(void)fprintf(stderr,
1802639ae9bSBen Gras 			    "mpool_get: page %d already pinned\n", bp->pgno);
1812639ae9bSBen Gras 			abort();
1822639ae9bSBen Gras 		}
1832639ae9bSBen Gras #endif
1842639ae9bSBen Gras 		/*
1852639ae9bSBen Gras 		 * Move the page to the head of the hash chain and the tail
1862639ae9bSBen Gras 		 * of the lru chain.
1872639ae9bSBen Gras 		 */
1882639ae9bSBen Gras 		head = &mp->hqh[HASHKEY(bp->pgno)];
18984d9c625SLionel Sambuc 		TAILQ_REMOVE(head, bp, hq);
19084d9c625SLionel Sambuc 		TAILQ_INSERT_HEAD(head, bp, hq);
19184d9c625SLionel Sambuc 		TAILQ_REMOVE(&mp->lqh, bp, q);
19284d9c625SLionel Sambuc 		TAILQ_INSERT_TAIL(&mp->lqh, bp, q);
1932639ae9bSBen Gras 
1942639ae9bSBen Gras 		/* Return a pinned page. */
1952639ae9bSBen Gras 		bp->flags |= MPOOL_PINNED;
196*0a6a1f1dSLionel Sambuc 		return bp->page;
1972639ae9bSBen Gras 	}
1982639ae9bSBen Gras 
1992639ae9bSBen Gras 	/* Get a page from the cache. */
2002639ae9bSBen Gras 	if ((bp = mpool_bkt(mp)) == NULL)
201*0a6a1f1dSLionel Sambuc 		return NULL;
2022639ae9bSBen Gras 
2032639ae9bSBen Gras 	/* Read in the contents. */
2042639ae9bSBen Gras #ifdef STATISTICS
2052639ae9bSBen Gras 	++mp->pageread;
2062639ae9bSBen Gras #endif
2072639ae9bSBen Gras 	off = mp->pagesize * pgno;
2082639ae9bSBen Gras 	if ((nr = pread(mp->fd, bp->page, (size_t)mp->pagesize, off)) != (int)mp->pagesize) {
2092639ae9bSBen Gras 		if (nr >= 0)
2102639ae9bSBen Gras 			errno = EFTYPE;
211*0a6a1f1dSLionel Sambuc 		return NULL;
2122639ae9bSBen Gras 	}
2132639ae9bSBen Gras 
2142639ae9bSBen Gras 	/* Set the page number, pin the page. */
2152639ae9bSBen Gras 	bp->pgno = pgno;
2162639ae9bSBen Gras 	bp->flags = MPOOL_PINNED;
2172639ae9bSBen Gras 
2182639ae9bSBen Gras 	/*
2192639ae9bSBen Gras 	 * Add the page to the head of the hash chain and the tail
2202639ae9bSBen Gras 	 * of the lru chain.
2212639ae9bSBen Gras 	 */
2222639ae9bSBen Gras 	head = &mp->hqh[HASHKEY(bp->pgno)];
22384d9c625SLionel Sambuc 	TAILQ_INSERT_HEAD(head, bp, hq);
22484d9c625SLionel Sambuc 	TAILQ_INSERT_TAIL(&mp->lqh, bp, q);
2252639ae9bSBen Gras 
2262639ae9bSBen Gras 	/* Run through the user's filter. */
2272639ae9bSBen Gras 	if (mp->pgin != NULL)
2282639ae9bSBen Gras 		(mp->pgin)(mp->pgcookie, bp->pgno, bp->page);
2292639ae9bSBen Gras 
230*0a6a1f1dSLionel Sambuc 	return bp->page;
2312639ae9bSBen Gras }
2322639ae9bSBen Gras 
2332639ae9bSBen Gras /*
2342639ae9bSBen Gras  * mpool_put
2352639ae9bSBen Gras  *	Return a page.
2362639ae9bSBen Gras  */
2372639ae9bSBen Gras /*ARGSUSED*/
2382639ae9bSBen Gras int
mpool_put(MPOOL * mp,void * page,u_int flags)2392639ae9bSBen Gras mpool_put(MPOOL *mp, void *page, u_int flags)
2402639ae9bSBen Gras {
2412639ae9bSBen Gras 	BKT *bp;
2422639ae9bSBen Gras 
2432639ae9bSBen Gras #ifdef STATISTICS
2442639ae9bSBen Gras 	++mp->pageput;
2452639ae9bSBen Gras #endif
246*0a6a1f1dSLionel Sambuc 	bp = (void *)((intptr_t)page - sizeof(BKT));
2472639ae9bSBen Gras #ifdef DEBUG
2482639ae9bSBen Gras 	if (!(bp->flags & MPOOL_PINNED)) {
2492639ae9bSBen Gras 		(void)fprintf(stderr,
2502639ae9bSBen Gras 		    "mpool_put: page %d not pinned\n", bp->pgno);
2512639ae9bSBen Gras 		abort();
2522639ae9bSBen Gras 	}
2532639ae9bSBen Gras #endif
2542639ae9bSBen Gras 	bp->flags &= ~MPOOL_PINNED;
2552639ae9bSBen Gras 	bp->flags |= flags & MPOOL_DIRTY;
2562639ae9bSBen Gras 	return (RET_SUCCESS);
2572639ae9bSBen Gras }
2582639ae9bSBen Gras 
2592639ae9bSBen Gras /*
2602639ae9bSBen Gras  * mpool_close
2612639ae9bSBen Gras  *	Close the buffer pool.
2622639ae9bSBen Gras  */
2632639ae9bSBen Gras int
mpool_close(MPOOL * mp)2642639ae9bSBen Gras mpool_close(MPOOL *mp)
2652639ae9bSBen Gras {
2662639ae9bSBen Gras 	BKT *bp;
2672639ae9bSBen Gras 
2682639ae9bSBen Gras 	/* Free up any space allocated to the lru pages. */
26984d9c625SLionel Sambuc 	while (!TAILQ_EMPTY(&mp->lqh)) {
27084d9c625SLionel Sambuc 		bp = TAILQ_FIRST(&mp->lqh);
27184d9c625SLionel Sambuc 		TAILQ_REMOVE(&mp->lqh, bp, q);
2722639ae9bSBen Gras 		free(bp);
2732639ae9bSBen Gras 	}
2742639ae9bSBen Gras 
2752639ae9bSBen Gras 	/* Free the MPOOL cookie. */
2762639ae9bSBen Gras 	free(mp);
277*0a6a1f1dSLionel Sambuc 	return RET_SUCCESS;
2782639ae9bSBen Gras }
2792639ae9bSBen Gras 
2802639ae9bSBen Gras /*
2812639ae9bSBen Gras  * mpool_sync
2822639ae9bSBen Gras  *	Sync the pool to disk.
2832639ae9bSBen Gras  */
2842639ae9bSBen Gras int
mpool_sync(MPOOL * mp)2852639ae9bSBen Gras mpool_sync(MPOOL *mp)
2862639ae9bSBen Gras {
2872639ae9bSBen Gras 	BKT *bp;
2882639ae9bSBen Gras 
2892639ae9bSBen Gras 	/* Walk the lru chain, flushing any dirty pages to disk. */
29084d9c625SLionel Sambuc 	TAILQ_FOREACH(bp, &mp->lqh, q)
2912639ae9bSBen Gras 		if (bp->flags & MPOOL_DIRTY &&
2922639ae9bSBen Gras 		    mpool_write(mp, bp) == RET_ERROR)
293*0a6a1f1dSLionel Sambuc 			return RET_ERROR;
2942639ae9bSBen Gras 
2952639ae9bSBen Gras 	/* Sync the file descriptor. */
296*0a6a1f1dSLionel Sambuc 	return fsync(mp->fd) ? RET_ERROR : RET_SUCCESS;
2972639ae9bSBen Gras }
2982639ae9bSBen Gras 
2992639ae9bSBen Gras /*
3002639ae9bSBen Gras  * mpool_bkt
3012639ae9bSBen Gras  *	Get a page from the cache (or create one).
3022639ae9bSBen Gras  */
3032639ae9bSBen Gras static BKT *
mpool_bkt(MPOOL * mp)3042639ae9bSBen Gras mpool_bkt(MPOOL *mp)
3052639ae9bSBen Gras {
3062639ae9bSBen Gras 	struct _hqh *head;
3072639ae9bSBen Gras 	BKT *bp;
3082639ae9bSBen Gras 
3092639ae9bSBen Gras 	/* If under the max cached, always create a new page. */
3102639ae9bSBen Gras 	if (mp->curcache < mp->maxcache)
3112639ae9bSBen Gras 		goto new;
3122639ae9bSBen Gras 
3132639ae9bSBen Gras 	/*
3142639ae9bSBen Gras 	 * If the cache is max'd out, walk the lru list for a buffer we
3152639ae9bSBen Gras 	 * can flush.  If we find one, write it (if necessary) and take it
3162639ae9bSBen Gras 	 * off any lists.  If we don't find anything we grow the cache anyway.
3172639ae9bSBen Gras 	 * The cache never shrinks.
3182639ae9bSBen Gras 	 */
31984d9c625SLionel Sambuc 	TAILQ_FOREACH(bp, &mp->lqh, q)
3202639ae9bSBen Gras 		if (!(bp->flags & MPOOL_PINNED)) {
3212639ae9bSBen Gras 			/* Flush if dirty. */
3222639ae9bSBen Gras 			if (bp->flags & MPOOL_DIRTY &&
3232639ae9bSBen Gras 			    mpool_write(mp, bp) == RET_ERROR)
324*0a6a1f1dSLionel Sambuc 				return NULL;
3252639ae9bSBen Gras #ifdef STATISTICS
3262639ae9bSBen Gras 			++mp->pageflush;
3272639ae9bSBen Gras #endif
3282639ae9bSBen Gras 			/* Remove from the hash and lru queues. */
3292639ae9bSBen Gras 			head = &mp->hqh[HASHKEY(bp->pgno)];
33084d9c625SLionel Sambuc 			TAILQ_REMOVE(head, bp, hq);
33184d9c625SLionel Sambuc 			TAILQ_REMOVE(&mp->lqh, bp, q);
3322639ae9bSBen Gras #ifdef DEBUG
3332639ae9bSBen Gras 			{
3342639ae9bSBen Gras 				void *spage = bp->page;
3352639ae9bSBen Gras 				(void)memset(bp, 0xff,
3362639ae9bSBen Gras 				    (size_t)(sizeof(BKT) + mp->pagesize));
3372639ae9bSBen Gras 				bp->page = spage;
3382639ae9bSBen Gras 			}
3392639ae9bSBen Gras #endif
340*0a6a1f1dSLionel Sambuc 			return bp;
3412639ae9bSBen Gras 		}
3422639ae9bSBen Gras 
3432639ae9bSBen Gras new:	if ((bp = calloc(1, (size_t)(sizeof(BKT) + mp->pagesize))) == NULL)
344*0a6a1f1dSLionel Sambuc 		return NULL;
3452639ae9bSBen Gras #ifdef STATISTICS
3462639ae9bSBen Gras 	++mp->pagealloc;
3472639ae9bSBen Gras #endif
3482639ae9bSBen Gras #if defined(DEBUG) || defined(PURIFY)
3492639ae9bSBen Gras 	(void)memset(bp, 0xff, (size_t)(sizeof(BKT) + mp->pagesize));
3502639ae9bSBen Gras #endif
351*0a6a1f1dSLionel Sambuc 	bp->page = (void *)((intptr_t)bp + sizeof(BKT));
3522639ae9bSBen Gras 	++mp->curcache;
353*0a6a1f1dSLionel Sambuc 	return bp;
3542639ae9bSBen Gras }
3552639ae9bSBen Gras 
3562639ae9bSBen Gras /*
3572639ae9bSBen Gras  * mpool_write
3582639ae9bSBen Gras  *	Write a page to disk.
3592639ae9bSBen Gras  */
3602639ae9bSBen Gras static int
mpool_write(MPOOL * mp,BKT * bp)3612639ae9bSBen Gras mpool_write(MPOOL *mp, BKT *bp)
3622639ae9bSBen Gras {
3632639ae9bSBen Gras 	off_t off;
3642639ae9bSBen Gras 
3652639ae9bSBen Gras #ifdef STATISTICS
3662639ae9bSBen Gras 	++mp->pagewrite;
3672639ae9bSBen Gras #endif
3682639ae9bSBen Gras 
3692639ae9bSBen Gras 	/* Run through the user's filter. */
3702639ae9bSBen Gras 	if (mp->pgout)
3712639ae9bSBen Gras 		(mp->pgout)(mp->pgcookie, bp->pgno, bp->page);
3722639ae9bSBen Gras 
3732639ae9bSBen Gras 	off = mp->pagesize * bp->pgno;
374*0a6a1f1dSLionel Sambuc 	if (pwrite(mp->fd, bp->page, (size_t)mp->pagesize, off) !=
375*0a6a1f1dSLionel Sambuc 	    (ssize_t)mp->pagesize)
376*0a6a1f1dSLionel Sambuc 		return RET_ERROR;
3772639ae9bSBen Gras 
3782639ae9bSBen Gras 	/*
3792639ae9bSBen Gras 	 * Re-run through the input filter since this page may soon be
3802639ae9bSBen Gras 	 * accessed via the cache, and whatever the user's output filter
3812639ae9bSBen Gras 	 * did may screw things up if we don't let the input filter
3822639ae9bSBen Gras 	 * restore the in-core copy.
3832639ae9bSBen Gras 	 */
3842639ae9bSBen Gras 	if (mp->pgin)
3852639ae9bSBen Gras 		(mp->pgin)(mp->pgcookie, bp->pgno, bp->page);
3862639ae9bSBen Gras 
3872639ae9bSBen Gras 	bp->flags &= ~MPOOL_DIRTY;
388*0a6a1f1dSLionel Sambuc 	return RET_SUCCESS;
3892639ae9bSBen Gras }
3902639ae9bSBen Gras 
3912639ae9bSBen Gras /*
3922639ae9bSBen Gras  * mpool_look
3932639ae9bSBen Gras  *	Lookup a page in the cache.
3942639ae9bSBen Gras  */
3952639ae9bSBen Gras static BKT *
mpool_look(MPOOL * mp,pgno_t pgno)3962639ae9bSBen Gras mpool_look(MPOOL *mp, pgno_t pgno)
3972639ae9bSBen Gras {
3982639ae9bSBen Gras 	struct _hqh *head;
3992639ae9bSBen Gras 	BKT *bp;
4002639ae9bSBen Gras 
4012639ae9bSBen Gras 	head = &mp->hqh[HASHKEY(pgno)];
40284d9c625SLionel Sambuc 	TAILQ_FOREACH(bp, head, hq)
4032639ae9bSBen Gras 		if (bp->pgno == pgno) {
4042639ae9bSBen Gras #ifdef STATISTICS
4052639ae9bSBen Gras 			++mp->cachehit;
4062639ae9bSBen Gras #endif
407*0a6a1f1dSLionel Sambuc 			return bp;
4082639ae9bSBen Gras 		}
4092639ae9bSBen Gras #ifdef STATISTICS
4102639ae9bSBen Gras 	++mp->cachemiss;
4112639ae9bSBen Gras #endif
412*0a6a1f1dSLionel Sambuc 	return NULL;
4132639ae9bSBen Gras }
4142639ae9bSBen Gras 
4152639ae9bSBen Gras #ifdef STATISTICS
4162639ae9bSBen Gras /*
4172639ae9bSBen Gras  * mpool_stat
4182639ae9bSBen Gras  *	Print out cache statistics.
4192639ae9bSBen Gras  */
4202639ae9bSBen Gras void
mpool_stat(mp)4212639ae9bSBen Gras mpool_stat(mp)
4222639ae9bSBen Gras 	MPOOL *mp;
4232639ae9bSBen Gras {
4242639ae9bSBen Gras 	BKT *bp;
4252639ae9bSBen Gras 	int cnt;
4262639ae9bSBen Gras 	const char *sep;
4272639ae9bSBen Gras 
4282639ae9bSBen Gras 	(void)fprintf(stderr, "%lu pages in the file\n", (u_long)mp->npages);
4292639ae9bSBen Gras 	(void)fprintf(stderr,
4302639ae9bSBen Gras 	    "page size %lu, cacheing %lu pages of %lu page max cache\n",
4312639ae9bSBen Gras 	    (u_long)mp->pagesize, (u_long)mp->curcache, (u_long)mp->maxcache);
4322639ae9bSBen Gras 	(void)fprintf(stderr, "%lu page puts, %lu page gets, %lu page new\n",
4332639ae9bSBen Gras 	    mp->pageput, mp->pageget, mp->pagenew);
4342639ae9bSBen Gras 	(void)fprintf(stderr, "%lu page allocs, %lu page flushes\n",
4352639ae9bSBen Gras 	    mp->pagealloc, mp->pageflush);
4362639ae9bSBen Gras 	if (mp->cachehit + mp->cachemiss)
4372639ae9bSBen Gras 		(void)fprintf(stderr,
4382639ae9bSBen Gras 		    "%.0f%% cache hit rate (%lu hits, %lu misses)\n",
4392639ae9bSBen Gras 		    ((double)mp->cachehit / (mp->cachehit + mp->cachemiss))
4402639ae9bSBen Gras 		    * 100, mp->cachehit, mp->cachemiss);
4412639ae9bSBen Gras 	(void)fprintf(stderr, "%lu page reads, %lu page writes\n",
4422639ae9bSBen Gras 	    mp->pageread, mp->pagewrite);
4432639ae9bSBen Gras 
4442639ae9bSBen Gras 	sep = "";
4452639ae9bSBen Gras 	cnt = 0;
44684d9c625SLionel Sambuc 	TAILQ_FOREACH(bp, &mp->lqh, q) {
4472639ae9bSBen Gras 		(void)fprintf(stderr, "%s%d", sep, bp->pgno);
4482639ae9bSBen Gras 		if (bp->flags & MPOOL_DIRTY)
4492639ae9bSBen Gras 			(void)fprintf(stderr, "d");
4502639ae9bSBen Gras 		if (bp->flags & MPOOL_PINNED)
4512639ae9bSBen Gras 			(void)fprintf(stderr, "P");
4522639ae9bSBen Gras 		if (++cnt == 10) {
4532639ae9bSBen Gras 			sep = "\n";
4542639ae9bSBen Gras 			cnt = 0;
4552639ae9bSBen Gras 		} else
4562639ae9bSBen Gras 			sep = ", ";
4572639ae9bSBen Gras 
4582639ae9bSBen Gras 	}
4592639ae9bSBen Gras 	(void)fprintf(stderr, "\n");
4602639ae9bSBen Gras }
4612639ae9bSBen Gras #endif
462