1*aae80e6bSchristos /* $NetBSD: mpool.c,v 1.23 2016/09/24 21:31:25 christos Exp $ */
22c84ad3aScgd
39f0aa214Scgd /*-
417140cefScgd * Copyright (c) 1990, 1993, 1994
59f0aa214Scgd * The Regents of the University of California. All rights reserved.
69f0aa214Scgd *
79f0aa214Scgd * Redistribution and use in source and binary forms, with or without
89f0aa214Scgd * modification, are permitted provided that the following conditions
99f0aa214Scgd * are met:
109f0aa214Scgd * 1. Redistributions of source code must retain the above copyright
119f0aa214Scgd * notice, this list of conditions and the following disclaimer.
129f0aa214Scgd * 2. Redistributions in binary form must reproduce the above copyright
139f0aa214Scgd * notice, this list of conditions and the following disclaimer in the
149f0aa214Scgd * documentation and/or other materials provided with the distribution.
15eb7c1594Sagc * 3. Neither the name of the University nor the names of its contributors
169f0aa214Scgd * may be used to endorse or promote products derived from this software
179f0aa214Scgd * without specific prior written permission.
189f0aa214Scgd *
199f0aa214Scgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
209f0aa214Scgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
219f0aa214Scgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
229f0aa214Scgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
239f0aa214Scgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
249f0aa214Scgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
259f0aa214Scgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
269f0aa214Scgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
279f0aa214Scgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
289f0aa214Scgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
299f0aa214Scgd * SUCH DAMAGE.
309f0aa214Scgd */
319f0aa214Scgd
32d3595ddfSjoerg #if HAVE_NBTOOL_CONFIG_H
33d3595ddfSjoerg #include "nbtool_config.h"
34d3595ddfSjoerg #endif
35d3595ddfSjoerg
3600ae392dSchristos #include <sys/cdefs.h>
37*aae80e6bSchristos __RCSID("$NetBSD: mpool.c,v 1.23 2016/09/24 21:31:25 christos Exp $");
389f0aa214Scgd
3943fa6fe3Sjtc #include "namespace.h"
4017140cefScgd #include <sys/queue.h>
419f0aa214Scgd #include <sys/stat.h>
429f0aa214Scgd
439f0aa214Scgd #include <errno.h>
449f0aa214Scgd #include <stdio.h>
459f0aa214Scgd #include <stdlib.h>
469f0aa214Scgd #include <string.h>
479f0aa214Scgd #include <unistd.h>
489f0aa214Scgd
499f0aa214Scgd #include <db.h>
5017140cefScgd
519f0aa214Scgd #define __MPOOLINTERFACE_PRIVATE
5217140cefScgd #include <mpool.h>
539f0aa214Scgd
5443fa6fe3Sjtc #ifdef __weak_alias
5560549036Smycroft __weak_alias(mpool_close,_mpool_close)
5660549036Smycroft __weak_alias(mpool_filter,_mpool_filter)
5760549036Smycroft __weak_alias(mpool_get,_mpool_get)
5860549036Smycroft __weak_alias(mpool_new,_mpool_new)
5986147b1cSchristos __weak_alias(mpool_newf,_mpool_newf)
6060549036Smycroft __weak_alias(mpool_open,_mpool_open)
6160549036Smycroft __weak_alias(mpool_put,_mpool_put)
6260549036Smycroft __weak_alias(mpool_sync,_mpool_sync)
6343fa6fe3Sjtc #endif
6443fa6fe3Sjtc
65cb9daf8fSchristos static BKT *mpool_bkt(MPOOL *);
66cb9daf8fSchristos static BKT *mpool_look(MPOOL *, pgno_t);
67cb9daf8fSchristos static int mpool_write(MPOOL *, BKT *);
689f0aa214Scgd
699f0aa214Scgd /*
7017140cefScgd * mpool_open --
7117140cefScgd * Initialize a memory pool.
729f0aa214Scgd */
7361238e71Schristos /*ARGSUSED*/
749f0aa214Scgd MPOOL *
mpool_open(void * key,int fd,pgno_t pagesize,pgno_t maxcache)75cb9daf8fSchristos mpool_open(void *key, int fd, pgno_t pagesize, pgno_t maxcache)
769f0aa214Scgd {
779f0aa214Scgd struct stat sb;
789f0aa214Scgd MPOOL *mp;
799f0aa214Scgd int entry;
809f0aa214Scgd
8117140cefScgd /*
8217140cefScgd * Get information about the file.
8317140cefScgd *
8417140cefScgd * XXX
8517140cefScgd * We don't currently handle pipes, although we should.
8617140cefScgd */
879f0aa214Scgd if (fstat(fd, &sb))
884008ee50Schristos return NULL;
899f0aa214Scgd if (!S_ISREG(sb.st_mode)) {
909f0aa214Scgd errno = ESPIPE;
914008ee50Schristos return NULL;
929f0aa214Scgd }
939f0aa214Scgd
9417140cefScgd /* Allocate and initialize the MPOOL cookie. */
954008ee50Schristos if ((mp = calloc(1, sizeof(*mp))) == NULL)
969f0aa214Scgd return (NULL);
97c64e7224Schristos TAILQ_INIT(&mp->lqh);
989f0aa214Scgd for (entry = 0; entry < HASHSIZE; ++entry)
99c64e7224Schristos TAILQ_INIT(&mp->hqh[entry]);
1009f0aa214Scgd mp->maxcache = maxcache;
10161238e71Schristos mp->npages = (pgno_t)(sb.st_size / pagesize);
10217140cefScgd mp->pagesize = pagesize;
1039f0aa214Scgd mp->fd = fd;
1044008ee50Schristos return mp;
1059f0aa214Scgd }
1069f0aa214Scgd
1079f0aa214Scgd /*
10817140cefScgd * mpool_filter --
10917140cefScgd * Initialize input/output filters.
1109f0aa214Scgd */
1119f0aa214Scgd void
mpool_filter(MPOOL * mp,void (* pgin)(void *,pgno_t,void *),void (* pgout)(void *,pgno_t,void *),void * pgcookie)112cb9daf8fSchristos mpool_filter(MPOOL *mp, void (*pgin)(void *, pgno_t, void *),
113cb9daf8fSchristos void (*pgout)(void *, pgno_t, void *), void *pgcookie)
1149f0aa214Scgd {
1159f0aa214Scgd mp->pgin = pgin;
1169f0aa214Scgd mp->pgout = pgout;
1179f0aa214Scgd mp->pgcookie = pgcookie;
1189f0aa214Scgd }
1199f0aa214Scgd
1209f0aa214Scgd /*
12117140cefScgd * mpool_new --
12217140cefScgd * Get a new page of memory.
1239f0aa214Scgd */
1249f0aa214Scgd void *
mpool_newf(MPOOL * mp,pgno_t * pgnoaddr,unsigned int flags)12586147b1cSchristos mpool_newf(MPOOL *mp, pgno_t *pgnoaddr, unsigned int flags)
1269f0aa214Scgd {
12717140cefScgd struct _hqh *head;
12817140cefScgd BKT *bp;
1299f0aa214Scgd
13017140cefScgd if (mp->npages == MAX_PAGE_NUMBER) {
13117140cefScgd (void)fprintf(stderr, "mpool_new: page allocation overflow.\n");
13217140cefScgd abort();
13317140cefScgd }
1349f0aa214Scgd #ifdef STATISTICS
1359f0aa214Scgd ++mp->pagenew;
1369f0aa214Scgd #endif
1379f0aa214Scgd /*
13817140cefScgd * Get a BKT from the cache. Assign a new page number, attach
13917140cefScgd * it to the head of the hash chain, the tail of the lru chain,
14017140cefScgd * and return.
1419f0aa214Scgd */
14217140cefScgd if ((bp = mpool_bkt(mp)) == NULL)
1434008ee50Schristos return NULL;
14486147b1cSchristos
14586147b1cSchristos if (flags == MPOOL_PAGE_REQUEST) {
14686147b1cSchristos mp->npages++;
14786147b1cSchristos bp->pgno = *pgnoaddr;
14886147b1cSchristos } else
14986147b1cSchristos bp->pgno = *pgnoaddr = mp->npages++;
15086147b1cSchristos
15186147b1cSchristos bp->flags = MPOOL_PINNED | MPOOL_INUSE;
15217140cefScgd
15317140cefScgd head = &mp->hqh[HASHKEY(bp->pgno)];
154c64e7224Schristos TAILQ_INSERT_HEAD(head, bp, hq);
155c64e7224Schristos TAILQ_INSERT_TAIL(&mp->lqh, bp, q);
1564008ee50Schristos return bp->page;
1579f0aa214Scgd }
1589f0aa214Scgd
15986147b1cSchristos void *
mpool_new(MPOOL * mp,pgno_t * pgnoaddr)16086147b1cSchristos mpool_new(MPOOL *mp, pgno_t *pgnoaddr)
16186147b1cSchristos {
16286147b1cSchristos return mpool_newf(mp, pgnoaddr, 0);
16386147b1cSchristos }
16486147b1cSchristos
16586147b1cSchristos int
mpool_delete(MPOOL * mp,void * page)16686147b1cSchristos mpool_delete(MPOOL *mp, void *page)
16786147b1cSchristos {
16886147b1cSchristos struct _hqh *head;
16986147b1cSchristos BKT *bp;
17086147b1cSchristos
17186147b1cSchristos bp = (void *)((char *)page - sizeof(BKT));
17286147b1cSchristos
17386147b1cSchristos #ifdef DEBUG
17486147b1cSchristos if (!(bp->flags & MPOOL_PINNED)) {
17586147b1cSchristos (void)fprintf(stderr,
17686147b1cSchristos "%s: page %d not pinned\n", __func__, bp->pgno);
17786147b1cSchristos abort();
17886147b1cSchristos }
17986147b1cSchristos #endif
18086147b1cSchristos
18186147b1cSchristos /* Remove from the hash and lru queues. */
18286147b1cSchristos head = &mp->hqh[HASHKEY(bp->pgno)];
18386147b1cSchristos TAILQ_REMOVE(head, bp, hq);
18486147b1cSchristos TAILQ_REMOVE(&mp->lqh, bp, q);
18586147b1cSchristos
18686147b1cSchristos free(bp);
18786147b1cSchristos return RET_SUCCESS;
18886147b1cSchristos }
18986147b1cSchristos
1909f0aa214Scgd /*
19117140cefScgd * mpool_get
19217140cefScgd * Get a page.
1939f0aa214Scgd */
19461238e71Schristos /*ARGSUSED*/
1959f0aa214Scgd void *
mpool_get(MPOOL * mp,pgno_t pgno,unsigned int flags)196*aae80e6bSchristos mpool_get(MPOOL *mp, pgno_t pgno, unsigned int flags)
1979f0aa214Scgd {
19817140cefScgd struct _hqh *head;
19917140cefScgd BKT *bp;
2009f0aa214Scgd off_t off;
201cb9daf8fSchristos ssize_t nr;
2029f0aa214Scgd
20317140cefScgd /* Check for attempt to retrieve a non-existent page. */
2049f0aa214Scgd if (pgno >= mp->npages) {
2059f0aa214Scgd errno = EINVAL;
2064008ee50Schristos return NULL;
2079f0aa214Scgd }
2089f0aa214Scgd
20917140cefScgd #ifdef STATISTICS
21017140cefScgd ++mp->pageget;
21117140cefScgd #endif
2129f0aa214Scgd
21317140cefScgd /* Check for a page that is cached. */
21417140cefScgd if ((bp = mpool_look(mp, pgno)) != NULL) {
21517140cefScgd #ifdef DEBUG
21686147b1cSchristos if (!(flags & MPOOL_IGNOREPIN) && bp->flags & MPOOL_PINNED) {
21717140cefScgd (void)fprintf(stderr,
21817140cefScgd "mpool_get: page %d already pinned\n", bp->pgno);
21917140cefScgd abort();
22017140cefScgd }
22117140cefScgd #endif
22217140cefScgd /*
22317140cefScgd * Move the page to the head of the hash chain and the tail
22417140cefScgd * of the lru chain.
22517140cefScgd */
22617140cefScgd head = &mp->hqh[HASHKEY(bp->pgno)];
227c64e7224Schristos TAILQ_REMOVE(head, bp, hq);
228c64e7224Schristos TAILQ_INSERT_HEAD(head, bp, hq);
229c64e7224Schristos TAILQ_REMOVE(&mp->lqh, bp, q);
230c64e7224Schristos TAILQ_INSERT_TAIL(&mp->lqh, bp, q);
23117140cefScgd
23217140cefScgd /* Return a pinned page. */
23386147b1cSchristos if (!(flags & MPOOL_IGNOREPIN))
23417140cefScgd bp->flags |= MPOOL_PINNED;
2354008ee50Schristos return bp->page;
23617140cefScgd }
23717140cefScgd
23817140cefScgd /* Get a page from the cache. */
23917140cefScgd if ((bp = mpool_bkt(mp)) == NULL)
2404008ee50Schristos return NULL;
24117140cefScgd
24217140cefScgd /* Read in the contents. */
2439f0aa214Scgd #ifdef STATISTICS
2449f0aa214Scgd ++mp->pageread;
2459f0aa214Scgd #endif
2469f0aa214Scgd off = mp->pagesize * pgno;
24786147b1cSchristos if (off / mp->pagesize != pgno) {
24886147b1cSchristos /* Run past the end of the file, or at least the part we
24986147b1cSchristos can address without large-file support? */
25086147b1cSchristos errno = E2BIG;
25186147b1cSchristos return NULL;
25286147b1cSchristos }
25386147b1cSchristos
25461238e71Schristos if ((nr = pread(mp->fd, bp->page, (size_t)mp->pagesize, off)) != (int)mp->pagesize) {
25586147b1cSchristos if (nr > 0) {
2569f0aa214Scgd errno = EFTYPE;
2574008ee50Schristos return NULL;
25886147b1cSchristos } else if (nr == 0) {
25986147b1cSchristos /*
26086147b1cSchristos * A zero-length reads, means you need to create a
26186147b1cSchristos * new page.
26286147b1cSchristos */
26386147b1cSchristos memset(bp->page, 0, mp->pagesize);
26486147b1cSchristos } else
26586147b1cSchristos return NULL;
2669f0aa214Scgd }
2679f0aa214Scgd
26817140cefScgd /* Set the page number, pin the page. */
26917140cefScgd bp->pgno = pgno;
27086147b1cSchristos if (!(flags & MPOOL_IGNOREPIN))
27117140cefScgd bp->flags = MPOOL_PINNED;
27286147b1cSchristos bp->flags |= MPOOL_INUSE;
27317140cefScgd
27417140cefScgd /*
27517140cefScgd * Add the page to the head of the hash chain and the tail
27617140cefScgd * of the lru chain.
27717140cefScgd */
27817140cefScgd head = &mp->hqh[HASHKEY(bp->pgno)];
279c64e7224Schristos TAILQ_INSERT_HEAD(head, bp, hq);
280c64e7224Schristos TAILQ_INSERT_TAIL(&mp->lqh, bp, q);
28117140cefScgd
28217140cefScgd /* Run through the user's filter. */
28317140cefScgd if (mp->pgin != NULL)
28417140cefScgd (mp->pgin)(mp->pgcookie, bp->pgno, bp->page);
28517140cefScgd
2864008ee50Schristos return bp->page;
2879f0aa214Scgd }
2889f0aa214Scgd
2899f0aa214Scgd /*
29017140cefScgd * mpool_put
29117140cefScgd * Return a page.
2929f0aa214Scgd */
29361238e71Schristos /*ARGSUSED*/
2949f0aa214Scgd int
mpool_put(MPOOL * mp,void * page,u_int flags)295cb9daf8fSchristos mpool_put(MPOOL *mp, void *page, u_int flags)
2969f0aa214Scgd {
29717140cefScgd BKT *bp;
2989f0aa214Scgd
2999f0aa214Scgd #ifdef STATISTICS
3009f0aa214Scgd ++mp->pageput;
3019f0aa214Scgd #endif
3024008ee50Schristos bp = (void *)((intptr_t)page - sizeof(BKT));
3039f0aa214Scgd #ifdef DEBUG
30417140cefScgd if (!(bp->flags & MPOOL_PINNED)) {
30517140cefScgd (void)fprintf(stderr,
30617140cefScgd "mpool_put: page %d not pinned\n", bp->pgno);
30717140cefScgd abort();
3089f0aa214Scgd }
3099f0aa214Scgd #endif
31017140cefScgd bp->flags &= ~MPOOL_PINNED;
31186147b1cSchristos if (flags & MPOOL_DIRTY)
31217140cefScgd bp->flags |= flags & MPOOL_DIRTY;
3139f0aa214Scgd return (RET_SUCCESS);
3149f0aa214Scgd }
3159f0aa214Scgd
3169f0aa214Scgd /*
31717140cefScgd * mpool_close
31817140cefScgd * Close the buffer pool.
3199f0aa214Scgd */
3209f0aa214Scgd int
mpool_close(MPOOL * mp)321cb9daf8fSchristos mpool_close(MPOOL *mp)
3229f0aa214Scgd {
32317140cefScgd BKT *bp;
3249f0aa214Scgd
3259f0aa214Scgd /* Free up any space allocated to the lru pages. */
326c64e7224Schristos while (!TAILQ_EMPTY(&mp->lqh)) {
327c64e7224Schristos bp = TAILQ_FIRST(&mp->lqh);
328c64e7224Schristos TAILQ_REMOVE(&mp->lqh, bp, q);
32917140cefScgd free(bp);
3309f0aa214Scgd }
33117140cefScgd
33217140cefScgd /* Free the MPOOL cookie. */
3339f0aa214Scgd free(mp);
3344008ee50Schristos return RET_SUCCESS;
3359f0aa214Scgd }
3369f0aa214Scgd
3379f0aa214Scgd /*
33817140cefScgd * mpool_sync
33917140cefScgd * Sync the pool to disk.
3409f0aa214Scgd */
3419f0aa214Scgd int
mpool_sync(MPOOL * mp)342cb9daf8fSchristos mpool_sync(MPOOL *mp)
3439f0aa214Scgd {
34417140cefScgd BKT *bp;
3459f0aa214Scgd
34617140cefScgd /* Walk the lru chain, flushing any dirty pages to disk. */
347c64e7224Schristos TAILQ_FOREACH(bp, &mp->lqh, q)
34817140cefScgd if (bp->flags & MPOOL_DIRTY &&
34917140cefScgd mpool_write(mp, bp) == RET_ERROR)
3504008ee50Schristos return RET_ERROR;
35117140cefScgd
35217140cefScgd /* Sync the file descriptor. */
3534008ee50Schristos return fsync(mp->fd) ? RET_ERROR : RET_SUCCESS;
3549f0aa214Scgd }
3559f0aa214Scgd
3569f0aa214Scgd /*
35717140cefScgd * mpool_bkt
35817140cefScgd * Get a page from the cache (or create one).
3599f0aa214Scgd */
3609f0aa214Scgd static BKT *
mpool_bkt(MPOOL * mp)361cb9daf8fSchristos mpool_bkt(MPOOL *mp)
3629f0aa214Scgd {
36317140cefScgd struct _hqh *head;
36417140cefScgd BKT *bp;
3659f0aa214Scgd
36617140cefScgd /* If under the max cached, always create a new page. */
3679f0aa214Scgd if (mp->curcache < mp->maxcache)
3689f0aa214Scgd goto new;
3699f0aa214Scgd
3709f0aa214Scgd /*
37117140cefScgd * If the cache is max'd out, walk the lru list for a buffer we
37217140cefScgd * can flush. If we find one, write it (if necessary) and take it
37317140cefScgd * off any lists. If we don't find anything we grow the cache anyway.
3749f0aa214Scgd * The cache never shrinks.
3759f0aa214Scgd */
376c64e7224Schristos TAILQ_FOREACH(bp, &mp->lqh, q)
37717140cefScgd if (!(bp->flags & MPOOL_PINNED)) {
37817140cefScgd /* Flush if dirty. */
37917140cefScgd if (bp->flags & MPOOL_DIRTY &&
38017140cefScgd mpool_write(mp, bp) == RET_ERROR)
3814008ee50Schristos return NULL;
3829f0aa214Scgd #ifdef STATISTICS
3839f0aa214Scgd ++mp->pageflush;
3849f0aa214Scgd #endif
38517140cefScgd /* Remove from the hash and lru queues. */
38617140cefScgd head = &mp->hqh[HASHKEY(bp->pgno)];
387c64e7224Schristos TAILQ_REMOVE(head, bp, hq);
388c64e7224Schristos TAILQ_REMOVE(&mp->lqh, bp, q);
3899f0aa214Scgd #ifdef DEBUG
390096020daSchristos {
391096020daSchristos void *spage = bp->page;
392096020daSchristos (void)memset(bp, 0xff,
393096020daSchristos (size_t)(sizeof(BKT) + mp->pagesize));
39417140cefScgd bp->page = spage;
3959f0aa214Scgd }
3969f0aa214Scgd #endif
3974008ee50Schristos return bp;
3989f0aa214Scgd }
3999f0aa214Scgd
4000f03f83aSchristos new: if ((bp = calloc(1, (size_t)(sizeof(BKT) + mp->pagesize))) == NULL)
4014008ee50Schristos return NULL;
4029f0aa214Scgd #ifdef STATISTICS
4039f0aa214Scgd ++mp->pagealloc;
4049f0aa214Scgd #endif
40517140cefScgd #if defined(DEBUG) || defined(PURIFY)
406096020daSchristos (void)memset(bp, 0xff, (size_t)(sizeof(BKT) + mp->pagesize));
4079f0aa214Scgd #endif
4084008ee50Schristos bp->page = (void *)((intptr_t)bp + sizeof(BKT));
4099f0aa214Scgd ++mp->curcache;
4104008ee50Schristos return bp;
4119f0aa214Scgd }
4129f0aa214Scgd
4139f0aa214Scgd /*
41417140cefScgd * mpool_write
41517140cefScgd * Write a page to disk.
4169f0aa214Scgd */
4179f0aa214Scgd static int
mpool_write(MPOOL * mp,BKT * bp)418cb9daf8fSchristos mpool_write(MPOOL *mp, BKT *bp)
4199f0aa214Scgd {
4209f0aa214Scgd off_t off;
4219f0aa214Scgd
4229f0aa214Scgd #ifdef STATISTICS
4239f0aa214Scgd ++mp->pagewrite;
4249f0aa214Scgd #endif
42517140cefScgd
42617140cefScgd /* Run through the user's filter. */
42717140cefScgd if (mp->pgout)
42817140cefScgd (mp->pgout)(mp->pgcookie, bp->pgno, bp->page);
42917140cefScgd
43017140cefScgd off = mp->pagesize * bp->pgno;
43186147b1cSchristos if (off / mp->pagesize != bp->pgno) {
43286147b1cSchristos /* Run past the end of the file, or at least the part we
43386147b1cSchristos can address without large-file support? */
43486147b1cSchristos errno = E2BIG;
43586147b1cSchristos return RET_ERROR;
43686147b1cSchristos }
43786147b1cSchristos
4384008ee50Schristos if (pwrite(mp->fd, bp->page, (size_t)mp->pagesize, off) !=
4394008ee50Schristos (ssize_t)mp->pagesize)
4404008ee50Schristos return RET_ERROR;
44117140cefScgd
4422a8d4256Sscw /*
4432a8d4256Sscw * Re-run through the input filter since this page may soon be
4442a8d4256Sscw * accessed via the cache, and whatever the user's output filter
4452a8d4256Sscw * did may screw things up if we don't let the input filter
4462a8d4256Sscw * restore the in-core copy.
4472a8d4256Sscw */
4482a8d4256Sscw if (mp->pgin)
4492a8d4256Sscw (mp->pgin)(mp->pgcookie, bp->pgno, bp->page);
4502a8d4256Sscw
45117140cefScgd bp->flags &= ~MPOOL_DIRTY;
4524008ee50Schristos return RET_SUCCESS;
4539f0aa214Scgd }
4549f0aa214Scgd
4559f0aa214Scgd /*
45617140cefScgd * mpool_look
45717140cefScgd * Lookup a page in the cache.
4589f0aa214Scgd */
4599f0aa214Scgd static BKT *
mpool_look(MPOOL * mp,pgno_t pgno)460cb9daf8fSchristos mpool_look(MPOOL *mp, pgno_t pgno)
4619f0aa214Scgd {
46217140cefScgd struct _hqh *head;
46317140cefScgd BKT *bp;
4649f0aa214Scgd
46517140cefScgd head = &mp->hqh[HASHKEY(pgno)];
466c64e7224Schristos TAILQ_FOREACH(bp, head, hq)
46717140cefScgd if (bp->pgno == pgno) {
4689f0aa214Scgd #ifdef STATISTICS
4699f0aa214Scgd ++mp->cachehit;
4709f0aa214Scgd #endif
4714008ee50Schristos return bp;
4729f0aa214Scgd }
4739f0aa214Scgd #ifdef STATISTICS
4749f0aa214Scgd ++mp->cachemiss;
4759f0aa214Scgd #endif
4764008ee50Schristos return NULL;
4779f0aa214Scgd }
4789f0aa214Scgd
4799f0aa214Scgd #ifdef STATISTICS
4809f0aa214Scgd /*
48117140cefScgd * mpool_stat
48217140cefScgd * Print out cache statistics.
4839f0aa214Scgd */
4849f0aa214Scgd void
mpool_stat(mp)4859f0aa214Scgd mpool_stat(mp)
4869f0aa214Scgd MPOOL *mp;
4879f0aa214Scgd {
48817140cefScgd BKT *bp;
4899f0aa214Scgd int cnt;
490cb9daf8fSchristos const char *sep;
4919f0aa214Scgd
492cb9daf8fSchristos (void)fprintf(stderr, "%lu pages in the file\n", (u_long)mp->npages);
4939f0aa214Scgd (void)fprintf(stderr,
4949f0aa214Scgd "page size %lu, cacheing %lu pages of %lu page max cache\n",
495cb9daf8fSchristos (u_long)mp->pagesize, (u_long)mp->curcache, (u_long)mp->maxcache);
4969f0aa214Scgd (void)fprintf(stderr, "%lu page puts, %lu page gets, %lu page new\n",
4979f0aa214Scgd mp->pageput, mp->pageget, mp->pagenew);
4989f0aa214Scgd (void)fprintf(stderr, "%lu page allocs, %lu page flushes\n",
4999f0aa214Scgd mp->pagealloc, mp->pageflush);
5009f0aa214Scgd if (mp->cachehit + mp->cachemiss)
5019f0aa214Scgd (void)fprintf(stderr,
5029f0aa214Scgd "%.0f%% cache hit rate (%lu hits, %lu misses)\n",
5039f0aa214Scgd ((double)mp->cachehit / (mp->cachehit + mp->cachemiss))
5049f0aa214Scgd * 100, mp->cachehit, mp->cachemiss);
5059f0aa214Scgd (void)fprintf(stderr, "%lu page reads, %lu page writes\n",
5069f0aa214Scgd mp->pageread, mp->pagewrite);
5079f0aa214Scgd
5089f0aa214Scgd sep = "";
5099f0aa214Scgd cnt = 0;
510c64e7224Schristos TAILQ_FOREACH(bp, &mp->lqh, q) {
51117140cefScgd (void)fprintf(stderr, "%s%d", sep, bp->pgno);
51217140cefScgd if (bp->flags & MPOOL_DIRTY)
5139f0aa214Scgd (void)fprintf(stderr, "d");
51417140cefScgd if (bp->flags & MPOOL_PINNED)
5159f0aa214Scgd (void)fprintf(stderr, "P");
5169f0aa214Scgd if (++cnt == 10) {
5179f0aa214Scgd sep = "\n";
5189f0aa214Scgd cnt = 0;
5199f0aa214Scgd } else
5209f0aa214Scgd sep = ", ";
5219f0aa214Scgd
5229f0aa214Scgd }
5239f0aa214Scgd (void)fprintf(stderr, "\n");
5249f0aa214Scgd }
5259f0aa214Scgd #endif
526