1 1.23 christos /* $NetBSD: mpool.c,v 1.23 2016/09/24 21:31:25 christos Exp $ */ 2 1.5 cgd 3 1.1 cgd /*- 4 1.6 cgd * Copyright (c) 1990, 1993, 1994 5 1.1 cgd * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * Redistribution and use in source and binary forms, with or without 8 1.1 cgd * modification, are permitted provided that the following conditions 9 1.1 cgd * are met: 10 1.1 cgd * 1. Redistributions of source code must retain the above copyright 11 1.1 cgd * notice, this list of conditions and the following disclaimer. 12 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 cgd * notice, this list of conditions and the following disclaimer in the 14 1.1 cgd * documentation and/or other materials provided with the distribution. 15 1.14 agc * 3. Neither the name of the University nor the names of its contributors 16 1.1 cgd * may be used to endorse or promote products derived from this software 17 1.1 cgd * without specific prior written permission. 18 1.1 cgd * 19 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 cgd * SUCH DAMAGE. 30 1.1 cgd */ 31 1.1 cgd 32 1.18 joerg #if HAVE_NBTOOL_CONFIG_H 33 1.18 joerg #include "nbtool_config.h" 34 1.18 joerg #endif 35 1.18 joerg 36 1.7 christos #include <sys/cdefs.h> 37 1.23 christos __RCSID("$NetBSD: mpool.c,v 1.23 2016/09/24 21:31:25 christos Exp $"); 38 1.1 cgd 39 1.8 jtc #include "namespace.h" 40 1.6 cgd #include <sys/queue.h> 41 1.1 cgd #include <sys/stat.h> 42 1.1 cgd 43 1.1 cgd #include <errno.h> 44 1.1 cgd #include <stdio.h> 45 1.1 cgd #include <stdlib.h> 46 1.1 cgd #include <string.h> 47 1.1 cgd #include <unistd.h> 48 1.1 cgd 49 1.1 cgd #include <db.h> 50 1.6 cgd 51 1.1 cgd #define __MPOOLINTERFACE_PRIVATE 52 1.6 cgd #include <mpool.h> 53 1.8 jtc 54 1.8 jtc #ifdef __weak_alias 55 1.12 mycroft __weak_alias(mpool_close,_mpool_close) 56 1.12 mycroft __weak_alias(mpool_filter,_mpool_filter) 57 1.12 mycroft __weak_alias(mpool_get,_mpool_get) 58 1.12 mycroft __weak_alias(mpool_new,_mpool_new) 59 1.22 christos __weak_alias(mpool_newf,_mpool_newf) 60 1.12 mycroft __weak_alias(mpool_open,_mpool_open) 61 1.12 mycroft __weak_alias(mpool_put,_mpool_put) 62 1.12 mycroft __weak_alias(mpool_sync,_mpool_sync) 63 1.8 jtc #endif 64 1.1 cgd 65 1.16 christos static BKT *mpool_bkt(MPOOL *); 66 1.16 christos static BKT *mpool_look(MPOOL *, pgno_t); 67 1.16 christos static int mpool_write(MPOOL *, BKT *); 68 1.1 cgd 69 1.1 cgd /* 70 1.6 cgd * mpool_open -- 71 1.6 cgd * Initialize a memory pool. 72 1.1 cgd */ 73 1.10 christos /*ARGSUSED*/ 74 1.1 cgd MPOOL * 75 1.16 christos mpool_open(void *key, int fd, pgno_t pagesize, pgno_t maxcache) 76 1.1 cgd { 77 1.1 cgd struct stat sb; 78 1.1 cgd MPOOL *mp; 79 1.1 cgd int entry; 80 1.1 cgd 81 1.6 cgd /* 82 1.6 cgd * Get information about the file. 83 1.6 cgd * 84 1.6 cgd * XXX 85 1.6 cgd * We don't currently handle pipes, although we should. 86 1.6 cgd */ 87 1.1 cgd if (fstat(fd, &sb)) 88 1.21 christos return NULL; 89 1.1 cgd if (!S_ISREG(sb.st_mode)) { 90 1.1 cgd errno = ESPIPE; 91 1.21 christos return NULL; 92 1.1 cgd } 93 1.1 cgd 94 1.6 cgd /* Allocate and initialize the MPOOL cookie. */ 95 1.21 christos if ((mp = calloc(1, sizeof(*mp))) == NULL) 96 1.1 cgd return (NULL); 97 1.20 christos TAILQ_INIT(&mp->lqh); 98 1.1 cgd for (entry = 0; entry < HASHSIZE; ++entry) 99 1.20 christos TAILQ_INIT(&mp->hqh[entry]); 100 1.1 cgd mp->maxcache = maxcache; 101 1.10 christos mp->npages = (pgno_t)(sb.st_size / pagesize); 102 1.1 cgd mp->pagesize = pagesize; 103 1.1 cgd mp->fd = fd; 104 1.21 christos return mp; 105 1.1 cgd } 106 1.1 cgd 107 1.1 cgd /* 108 1.6 cgd * mpool_filter -- 109 1.6 cgd * Initialize input/output filters. 110 1.1 cgd */ 111 1.1 cgd void 112 1.16 christos mpool_filter(MPOOL *mp, void (*pgin)(void *, pgno_t, void *), 113 1.16 christos void (*pgout)(void *, pgno_t, void *), void *pgcookie) 114 1.1 cgd { 115 1.1 cgd mp->pgin = pgin; 116 1.1 cgd mp->pgout = pgout; 117 1.1 cgd mp->pgcookie = pgcookie; 118 1.1 cgd } 119 1.1 cgd 120 1.1 cgd /* 121 1.6 cgd * mpool_new -- 122 1.6 cgd * Get a new page of memory. 123 1.1 cgd */ 124 1.1 cgd void * 125 1.22 christos mpool_newf(MPOOL *mp, pgno_t *pgnoaddr, unsigned int flags) 126 1.1 cgd { 127 1.6 cgd struct _hqh *head; 128 1.6 cgd BKT *bp; 129 1.1 cgd 130 1.6 cgd if (mp->npages == MAX_PAGE_NUMBER) { 131 1.6 cgd (void)fprintf(stderr, "mpool_new: page allocation overflow.\n"); 132 1.6 cgd abort(); 133 1.6 cgd } 134 1.1 cgd #ifdef STATISTICS 135 1.1 cgd ++mp->pagenew; 136 1.1 cgd #endif 137 1.1 cgd /* 138 1.6 cgd * Get a BKT from the cache. Assign a new page number, attach 139 1.6 cgd * it to the head of the hash chain, the tail of the lru chain, 140 1.6 cgd * and return. 141 1.1 cgd */ 142 1.6 cgd if ((bp = mpool_bkt(mp)) == NULL) 143 1.21 christos return NULL; 144 1.22 christos 145 1.22 christos if (flags == MPOOL_PAGE_REQUEST) { 146 1.22 christos mp->npages++; 147 1.22 christos bp->pgno = *pgnoaddr; 148 1.22 christos } else 149 1.22 christos bp->pgno = *pgnoaddr = mp->npages++; 150 1.22 christos 151 1.22 christos bp->flags = MPOOL_PINNED | MPOOL_INUSE; 152 1.6 cgd 153 1.6 cgd head = &mp->hqh[HASHKEY(bp->pgno)]; 154 1.20 christos TAILQ_INSERT_HEAD(head, bp, hq); 155 1.20 christos TAILQ_INSERT_TAIL(&mp->lqh, bp, q); 156 1.21 christos return bp->page; 157 1.1 cgd } 158 1.1 cgd 159 1.22 christos void * 160 1.22 christos mpool_new(MPOOL *mp, pgno_t *pgnoaddr) 161 1.22 christos { 162 1.22 christos return mpool_newf(mp, pgnoaddr, 0); 163 1.22 christos } 164 1.22 christos 165 1.22 christos int 166 1.22 christos mpool_delete(MPOOL *mp, void *page) 167 1.22 christos { 168 1.22 christos struct _hqh *head; 169 1.22 christos BKT *bp; 170 1.22 christos 171 1.22 christos bp = (void *)((char *)page - sizeof(BKT)); 172 1.22 christos 173 1.22 christos #ifdef DEBUG 174 1.22 christos if (!(bp->flags & MPOOL_PINNED)) { 175 1.22 christos (void)fprintf(stderr, 176 1.22 christos "%s: page %d not pinned\n", __func__, bp->pgno); 177 1.22 christos abort(); 178 1.22 christos } 179 1.22 christos #endif 180 1.22 christos 181 1.22 christos /* Remove from the hash and lru queues. */ 182 1.22 christos head = &mp->hqh[HASHKEY(bp->pgno)]; 183 1.22 christos TAILQ_REMOVE(head, bp, hq); 184 1.22 christos TAILQ_REMOVE(&mp->lqh, bp, q); 185 1.22 christos 186 1.22 christos free(bp); 187 1.22 christos return RET_SUCCESS; 188 1.22 christos } 189 1.22 christos 190 1.1 cgd /* 191 1.6 cgd * mpool_get 192 1.6 cgd * Get a page. 193 1.1 cgd */ 194 1.10 christos /*ARGSUSED*/ 195 1.1 cgd void * 196 1.23 christos mpool_get(MPOOL *mp, pgno_t pgno, unsigned int flags) 197 1.1 cgd { 198 1.6 cgd struct _hqh *head; 199 1.6 cgd BKT *bp; 200 1.1 cgd off_t off; 201 1.16 christos ssize_t nr; 202 1.1 cgd 203 1.6 cgd /* Check for attempt to retrieve a non-existent page. */ 204 1.6 cgd if (pgno >= mp->npages) { 205 1.6 cgd errno = EINVAL; 206 1.21 christos return NULL; 207 1.6 cgd } 208 1.6 cgd 209 1.1 cgd #ifdef STATISTICS 210 1.6 cgd ++mp->pageget; 211 1.1 cgd #endif 212 1.6 cgd 213 1.6 cgd /* Check for a page that is cached. */ 214 1.6 cgd if ((bp = mpool_look(mp, pgno)) != NULL) { 215 1.1 cgd #ifdef DEBUG 216 1.22 christos if (!(flags & MPOOL_IGNOREPIN) && bp->flags & MPOOL_PINNED) { 217 1.6 cgd (void)fprintf(stderr, 218 1.6 cgd "mpool_get: page %d already pinned\n", bp->pgno); 219 1.6 cgd abort(); 220 1.6 cgd } 221 1.6 cgd #endif 222 1.6 cgd /* 223 1.6 cgd * Move the page to the head of the hash chain and the tail 224 1.6 cgd * of the lru chain. 225 1.6 cgd */ 226 1.6 cgd head = &mp->hqh[HASHKEY(bp->pgno)]; 227 1.20 christos TAILQ_REMOVE(head, bp, hq); 228 1.20 christos TAILQ_INSERT_HEAD(head, bp, hq); 229 1.20 christos TAILQ_REMOVE(&mp->lqh, bp, q); 230 1.20 christos TAILQ_INSERT_TAIL(&mp->lqh, bp, q); 231 1.6 cgd 232 1.6 cgd /* Return a pinned page. */ 233 1.22 christos if (!(flags & MPOOL_IGNOREPIN)) 234 1.22 christos bp->flags |= MPOOL_PINNED; 235 1.21 christos return bp->page; 236 1.1 cgd } 237 1.1 cgd 238 1.1 cgd /* Get a page from the cache. */ 239 1.6 cgd if ((bp = mpool_bkt(mp)) == NULL) 240 1.21 christos return NULL; 241 1.1 cgd 242 1.6 cgd /* Read in the contents. */ 243 1.1 cgd #ifdef STATISTICS 244 1.1 cgd ++mp->pageread; 245 1.1 cgd #endif 246 1.1 cgd off = mp->pagesize * pgno; 247 1.22 christos if (off / mp->pagesize != pgno) { 248 1.22 christos /* Run past the end of the file, or at least the part we 249 1.22 christos can address without large-file support? */ 250 1.22 christos errno = E2BIG; 251 1.22 christos return NULL; 252 1.22 christos } 253 1.22 christos 254 1.10 christos if ((nr = pread(mp->fd, bp->page, (size_t)mp->pagesize, off)) != (int)mp->pagesize) { 255 1.22 christos if (nr > 0) { 256 1.1 cgd errno = EFTYPE; 257 1.22 christos return NULL; 258 1.22 christos } else if (nr == 0) { 259 1.22 christos /* 260 1.22 christos * A zero-length reads, means you need to create a 261 1.22 christos * new page. 262 1.22 christos */ 263 1.22 christos memset(bp->page, 0, mp->pagesize); 264 1.22 christos } else 265 1.22 christos return NULL; 266 1.1 cgd } 267 1.1 cgd 268 1.6 cgd /* Set the page number, pin the page. */ 269 1.6 cgd bp->pgno = pgno; 270 1.22 christos if (!(flags & MPOOL_IGNOREPIN)) 271 1.22 christos bp->flags = MPOOL_PINNED; 272 1.22 christos bp->flags |= MPOOL_INUSE; 273 1.6 cgd 274 1.6 cgd /* 275 1.6 cgd * Add the page to the head of the hash chain and the tail 276 1.6 cgd * of the lru chain. 277 1.6 cgd */ 278 1.6 cgd head = &mp->hqh[HASHKEY(bp->pgno)]; 279 1.20 christos TAILQ_INSERT_HEAD(head, bp, hq); 280 1.20 christos TAILQ_INSERT_TAIL(&mp->lqh, bp, q); 281 1.6 cgd 282 1.6 cgd /* Run through the user's filter. */ 283 1.6 cgd if (mp->pgin != NULL) 284 1.6 cgd (mp->pgin)(mp->pgcookie, bp->pgno, bp->page); 285 1.6 cgd 286 1.21 christos return bp->page; 287 1.1 cgd } 288 1.1 cgd 289 1.1 cgd /* 290 1.6 cgd * mpool_put 291 1.6 cgd * Return a page. 292 1.1 cgd */ 293 1.10 christos /*ARGSUSED*/ 294 1.1 cgd int 295 1.16 christos mpool_put(MPOOL *mp, void *page, u_int flags) 296 1.1 cgd { 297 1.6 cgd BKT *bp; 298 1.1 cgd 299 1.1 cgd #ifdef STATISTICS 300 1.1 cgd ++mp->pageput; 301 1.1 cgd #endif 302 1.21 christos bp = (void *)((intptr_t)page - sizeof(BKT)); 303 1.1 cgd #ifdef DEBUG 304 1.6 cgd if (!(bp->flags & MPOOL_PINNED)) { 305 1.6 cgd (void)fprintf(stderr, 306 1.6 cgd "mpool_put: page %d not pinned\n", bp->pgno); 307 1.6 cgd abort(); 308 1.1 cgd } 309 1.1 cgd #endif 310 1.6 cgd bp->flags &= ~MPOOL_PINNED; 311 1.22 christos if (flags & MPOOL_DIRTY) 312 1.22 christos bp->flags |= flags & MPOOL_DIRTY; 313 1.1 cgd return (RET_SUCCESS); 314 1.1 cgd } 315 1.1 cgd 316 1.1 cgd /* 317 1.6 cgd * mpool_close 318 1.6 cgd * Close the buffer pool. 319 1.1 cgd */ 320 1.1 cgd int 321 1.16 christos mpool_close(MPOOL *mp) 322 1.1 cgd { 323 1.6 cgd BKT *bp; 324 1.1 cgd 325 1.1 cgd /* Free up any space allocated to the lru pages. */ 326 1.20 christos while (!TAILQ_EMPTY(&mp->lqh)) { 327 1.20 christos bp = TAILQ_FIRST(&mp->lqh); 328 1.20 christos TAILQ_REMOVE(&mp->lqh, bp, q); 329 1.6 cgd free(bp); 330 1.1 cgd } 331 1.6 cgd 332 1.6 cgd /* Free the MPOOL cookie. */ 333 1.1 cgd free(mp); 334 1.21 christos return RET_SUCCESS; 335 1.1 cgd } 336 1.1 cgd 337 1.1 cgd /* 338 1.6 cgd * mpool_sync 339 1.6 cgd * Sync the pool to disk. 340 1.1 cgd */ 341 1.1 cgd int 342 1.16 christos mpool_sync(MPOOL *mp) 343 1.1 cgd { 344 1.6 cgd BKT *bp; 345 1.1 cgd 346 1.6 cgd /* Walk the lru chain, flushing any dirty pages to disk. */ 347 1.20 christos TAILQ_FOREACH(bp, &mp->lqh, q) 348 1.6 cgd if (bp->flags & MPOOL_DIRTY && 349 1.6 cgd mpool_write(mp, bp) == RET_ERROR) 350 1.21 christos return RET_ERROR; 351 1.6 cgd 352 1.6 cgd /* Sync the file descriptor. */ 353 1.21 christos return fsync(mp->fd) ? RET_ERROR : RET_SUCCESS; 354 1.1 cgd } 355 1.1 cgd 356 1.1 cgd /* 357 1.6 cgd * mpool_bkt 358 1.6 cgd * Get a page from the cache (or create one). 359 1.1 cgd */ 360 1.1 cgd static BKT * 361 1.16 christos mpool_bkt(MPOOL *mp) 362 1.1 cgd { 363 1.6 cgd struct _hqh *head; 364 1.6 cgd BKT *bp; 365 1.1 cgd 366 1.6 cgd /* If under the max cached, always create a new page. */ 367 1.1 cgd if (mp->curcache < mp->maxcache) 368 1.1 cgd goto new; 369 1.1 cgd 370 1.1 cgd /* 371 1.6 cgd * If the cache is max'd out, walk the lru list for a buffer we 372 1.6 cgd * can flush. If we find one, write it (if necessary) and take it 373 1.6 cgd * off any lists. If we don't find anything we grow the cache anyway. 374 1.1 cgd * The cache never shrinks. 375 1.1 cgd */ 376 1.20 christos TAILQ_FOREACH(bp, &mp->lqh, q) 377 1.6 cgd if (!(bp->flags & MPOOL_PINNED)) { 378 1.6 cgd /* Flush if dirty. */ 379 1.6 cgd if (bp->flags & MPOOL_DIRTY && 380 1.6 cgd mpool_write(mp, bp) == RET_ERROR) 381 1.21 christos return NULL; 382 1.1 cgd #ifdef STATISTICS 383 1.1 cgd ++mp->pageflush; 384 1.1 cgd #endif 385 1.6 cgd /* Remove from the hash and lru queues. */ 386 1.6 cgd head = &mp->hqh[HASHKEY(bp->pgno)]; 387 1.20 christos TAILQ_REMOVE(head, bp, hq); 388 1.20 christos TAILQ_REMOVE(&mp->lqh, bp, q); 389 1.1 cgd #ifdef DEBUG 390 1.15 christos { 391 1.15 christos void *spage = bp->page; 392 1.15 christos (void)memset(bp, 0xff, 393 1.15 christos (size_t)(sizeof(BKT) + mp->pagesize)); 394 1.6 cgd bp->page = spage; 395 1.1 cgd } 396 1.1 cgd #endif 397 1.21 christos return bp; 398 1.1 cgd } 399 1.1 cgd 400 1.19 christos new: if ((bp = calloc(1, (size_t)(sizeof(BKT) + mp->pagesize))) == NULL) 401 1.21 christos return NULL; 402 1.1 cgd #ifdef STATISTICS 403 1.1 cgd ++mp->pagealloc; 404 1.1 cgd #endif 405 1.6 cgd #if defined(DEBUG) || defined(PURIFY) 406 1.15 christos (void)memset(bp, 0xff, (size_t)(sizeof(BKT) + mp->pagesize)); 407 1.1 cgd #endif 408 1.21 christos bp->page = (void *)((intptr_t)bp + sizeof(BKT)); 409 1.1 cgd ++mp->curcache; 410 1.21 christos return bp; 411 1.1 cgd } 412 1.1 cgd 413 1.1 cgd /* 414 1.6 cgd * mpool_write 415 1.6 cgd * Write a page to disk. 416 1.1 cgd */ 417 1.1 cgd static int 418 1.16 christos mpool_write(MPOOL *mp, BKT *bp) 419 1.1 cgd { 420 1.1 cgd off_t off; 421 1.1 cgd 422 1.1 cgd #ifdef STATISTICS 423 1.1 cgd ++mp->pagewrite; 424 1.1 cgd #endif 425 1.6 cgd 426 1.6 cgd /* Run through the user's filter. */ 427 1.6 cgd if (mp->pgout) 428 1.6 cgd (mp->pgout)(mp->pgcookie, bp->pgno, bp->page); 429 1.6 cgd 430 1.6 cgd off = mp->pagesize * bp->pgno; 431 1.22 christos if (off / mp->pagesize != bp->pgno) { 432 1.22 christos /* Run past the end of the file, or at least the part we 433 1.22 christos can address without large-file support? */ 434 1.22 christos errno = E2BIG; 435 1.22 christos return RET_ERROR; 436 1.22 christos } 437 1.22 christos 438 1.21 christos if (pwrite(mp->fd, bp->page, (size_t)mp->pagesize, off) != 439 1.21 christos (ssize_t)mp->pagesize) 440 1.21 christos return RET_ERROR; 441 1.11 scw 442 1.11 scw /* 443 1.11 scw * Re-run through the input filter since this page may soon be 444 1.11 scw * accessed via the cache, and whatever the user's output filter 445 1.11 scw * did may screw things up if we don't let the input filter 446 1.11 scw * restore the in-core copy. 447 1.11 scw */ 448 1.11 scw if (mp->pgin) 449 1.11 scw (mp->pgin)(mp->pgcookie, bp->pgno, bp->page); 450 1.6 cgd 451 1.6 cgd bp->flags &= ~MPOOL_DIRTY; 452 1.21 christos return RET_SUCCESS; 453 1.1 cgd } 454 1.1 cgd 455 1.1 cgd /* 456 1.6 cgd * mpool_look 457 1.6 cgd * Lookup a page in the cache. 458 1.1 cgd */ 459 1.1 cgd static BKT * 460 1.16 christos mpool_look(MPOOL *mp, pgno_t pgno) 461 1.1 cgd { 462 1.6 cgd struct _hqh *head; 463 1.6 cgd BKT *bp; 464 1.1 cgd 465 1.6 cgd head = &mp->hqh[HASHKEY(pgno)]; 466 1.20 christos TAILQ_FOREACH(bp, head, hq) 467 1.6 cgd if (bp->pgno == pgno) { 468 1.1 cgd #ifdef STATISTICS 469 1.1 cgd ++mp->cachehit; 470 1.1 cgd #endif 471 1.21 christos return bp; 472 1.1 cgd } 473 1.1 cgd #ifdef STATISTICS 474 1.1 cgd ++mp->cachemiss; 475 1.1 cgd #endif 476 1.21 christos return NULL; 477 1.1 cgd } 478 1.1 cgd 479 1.1 cgd #ifdef STATISTICS 480 1.1 cgd /* 481 1.6 cgd * mpool_stat 482 1.6 cgd * Print out cache statistics. 483 1.1 cgd */ 484 1.1 cgd void 485 1.1 cgd mpool_stat(mp) 486 1.1 cgd MPOOL *mp; 487 1.1 cgd { 488 1.6 cgd BKT *bp; 489 1.1 cgd int cnt; 490 1.16 christos const char *sep; 491 1.1 cgd 492 1.16 christos (void)fprintf(stderr, "%lu pages in the file\n", (u_long)mp->npages); 493 1.1 cgd (void)fprintf(stderr, 494 1.1 cgd "page size %lu, cacheing %lu pages of %lu page max cache\n", 495 1.16 christos (u_long)mp->pagesize, (u_long)mp->curcache, (u_long)mp->maxcache); 496 1.1 cgd (void)fprintf(stderr, "%lu page puts, %lu page gets, %lu page new\n", 497 1.1 cgd mp->pageput, mp->pageget, mp->pagenew); 498 1.1 cgd (void)fprintf(stderr, "%lu page allocs, %lu page flushes\n", 499 1.1 cgd mp->pagealloc, mp->pageflush); 500 1.1 cgd if (mp->cachehit + mp->cachemiss) 501 1.1 cgd (void)fprintf(stderr, 502 1.1 cgd "%.0f%% cache hit rate (%lu hits, %lu misses)\n", 503 1.1 cgd ((double)mp->cachehit / (mp->cachehit + mp->cachemiss)) 504 1.1 cgd * 100, mp->cachehit, mp->cachemiss); 505 1.1 cgd (void)fprintf(stderr, "%lu page reads, %lu page writes\n", 506 1.1 cgd mp->pageread, mp->pagewrite); 507 1.1 cgd 508 1.1 cgd sep = ""; 509 1.1 cgd cnt = 0; 510 1.20 christos TAILQ_FOREACH(bp, &mp->lqh, q) { 511 1.6 cgd (void)fprintf(stderr, "%s%d", sep, bp->pgno); 512 1.6 cgd if (bp->flags & MPOOL_DIRTY) 513 1.1 cgd (void)fprintf(stderr, "d"); 514 1.6 cgd if (bp->flags & MPOOL_PINNED) 515 1.1 cgd (void)fprintf(stderr, "P"); 516 1.1 cgd if (++cnt == 10) { 517 1.1 cgd sep = "\n"; 518 1.1 cgd cnt = 0; 519 1.1 cgd } else 520 1.1 cgd sep = ", "; 521 1.1 cgd 522 1.1 cgd } 523 1.1 cgd (void)fprintf(stderr, "\n"); 524 1.1 cgd } 525 1.1 cgd #endif 526