mpool.c (8870) | mpool.c (14287) |
---|---|
1/*- | 1/*- |
2 * Copyright (c) 1990, 1993 | 2 * Copyright (c) 1990, 1993, 1994 |
3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright --- 16 unchanged lines hidden (view full) --- 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#if defined(LIBC_SCCS) && !defined(lint) | 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright --- 16 unchanged lines hidden (view full) --- 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#if defined(LIBC_SCCS) && !defined(lint) |
35static char sccsid[] = "@(#)mpool.c 8.2 (Berkeley) 2/21/94"; | 35static char sccsid[] = "@(#)mpool.c 8.5 (Berkeley) 7/26/94"; |
36#endif /* LIBC_SCCS and not lint */ 37 38#include <sys/param.h> | 36#endif /* LIBC_SCCS and not lint */ 37 38#include <sys/param.h> |
39#include <sys/queue.h> |
|
39#include <sys/stat.h> 40 41#include <errno.h> 42#include <stdio.h> 43#include <stdlib.h> 44#include <string.h> 45#include <unistd.h> 46 47#include <db.h> | 40#include <sys/stat.h> 41 42#include <errno.h> 43#include <stdio.h> 44#include <stdlib.h> 45#include <string.h> 46#include <unistd.h> 47 48#include <db.h> |
49 |
|
48#define __MPOOLINTERFACE_PRIVATE | 50#define __MPOOLINTERFACE_PRIVATE |
49#include "mpool.h" | 51#include <mpool.h> |
50 51static BKT *mpool_bkt __P((MPOOL *)); 52static BKT *mpool_look __P((MPOOL *, pgno_t)); 53static int mpool_write __P((MPOOL *, BKT *)); | 52 53static BKT *mpool_bkt __P((MPOOL *)); 54static BKT *mpool_look __P((MPOOL *, pgno_t)); 55static int mpool_write __P((MPOOL *, BKT *)); |
54#ifdef DEBUG 55static void __mpoolerr __P((const char *fmt, ...)); 56#endif | |
57 58/* | 56 57/* |
59 * MPOOL_OPEN -- initialize a memory pool. 60 * 61 * Parameters: 62 * key: Shared buffer key. 63 * fd: File descriptor. 64 * pagesize: File page size. 65 * maxcache: Max number of cached pages. 66 * 67 * Returns: 68 * MPOOL pointer, NULL on error. | 58 * mpool_open -- 59 * Initialize a memory pool. |
69 */ 70MPOOL * 71mpool_open(key, fd, pagesize, maxcache) | 60 */ 61MPOOL * 62mpool_open(key, fd, pagesize, maxcache) |
72 DBT *key; | 63 void *key; |
73 int fd; 74 pgno_t pagesize, maxcache; 75{ 76 struct stat sb; 77 MPOOL *mp; 78 int entry; 79 | 64 int fd; 65 pgno_t pagesize, maxcache; 66{ 67 struct stat sb; 68 MPOOL *mp; 69 int entry; 70 |
71 /* 72 * Get information about the file. 73 * 74 * XXX 75 * We don't currently handle pipes, although we should. 76 */ |
|
80 if (fstat(fd, &sb)) 81 return (NULL); | 77 if (fstat(fd, &sb)) 78 return (NULL); |
82 /* XXX 83 * We should only set st_size to 0 for pipes -- 4.4BSD has the fix so 84 * that stat(2) returns true for ISSOCK on pipes. Until then, this is 85 * fairly close. 86 */ | |
87 if (!S_ISREG(sb.st_mode)) { 88 errno = ESPIPE; 89 return (NULL); 90 } 91 | 79 if (!S_ISREG(sb.st_mode)) { 80 errno = ESPIPE; 81 return (NULL); 82 } 83 |
92 if ((mp = (MPOOL *)malloc(sizeof(MPOOL))) == NULL) | 84 /* Allocate and initialize the MPOOL cookie. */ 85 if ((mp = (MPOOL *)calloc(1, sizeof(MPOOL))) == NULL) |
93 return (NULL); | 86 return (NULL); |
94 mp->free.cnext = mp->free.cprev = (BKT *)&mp->free; 95 mp->lru.cnext = mp->lru.cprev = (BKT *)&mp->lru; | 87 CIRCLEQ_INIT(&mp->lqh); |
96 for (entry = 0; entry < HASHSIZE; ++entry) | 88 for (entry = 0; entry < HASHSIZE; ++entry) |
97 mp->hashtable[entry].hnext = mp->hashtable[entry].hprev = 98 mp->hashtable[entry].cnext = mp->hashtable[entry].cprev = 99 (BKT *)&mp->hashtable[entry]; 100 mp->curcache = 0; | 89 CIRCLEQ_INIT(&mp->hqh[entry]); |
101 mp->maxcache = maxcache; | 90 mp->maxcache = maxcache; |
102 mp->pagesize = pagesize; | |
103 mp->npages = sb.st_size / pagesize; | 91 mp->npages = sb.st_size / pagesize; |
92 mp->pagesize = pagesize; |
|
104 mp->fd = fd; | 93 mp->fd = fd; |
105 mp->pgcookie = NULL; 106 mp->pgin = mp->pgout = NULL; 107 108#ifdef STATISTICS 109 mp->cachehit = mp->cachemiss = mp->pagealloc = mp->pageflush = 110 mp->pageget = mp->pagenew = mp->pageput = mp->pageread = 111 mp->pagewrite = 0; 112#endif | |
113 return (mp); 114} 115 116/* | 94 return (mp); 95} 96 97/* |
117 * MPOOL_FILTER -- initialize input/output filters. 118 * 119 * Parameters: 120 * pgin: Page in conversion routine. 121 * pgout: Page out conversion routine. 122 * pgcookie: Cookie for page in/out routines. | 98 * mpool_filter -- 99 * Initialize input/output filters. |
123 */ 124void 125mpool_filter(mp, pgin, pgout, pgcookie) 126 MPOOL *mp; 127 void (*pgin) __P((void *, pgno_t, void *)); 128 void (*pgout) __P((void *, pgno_t, void *)); 129 void *pgcookie; 130{ 131 mp->pgin = pgin; 132 mp->pgout = pgout; 133 mp->pgcookie = pgcookie; 134} | 100 */ 101void 102mpool_filter(mp, pgin, pgout, pgcookie) 103 MPOOL *mp; 104 void (*pgin) __P((void *, pgno_t, void *)); 105 void (*pgout) __P((void *, pgno_t, void *)); 106 void *pgcookie; 107{ 108 mp->pgin = pgin; 109 mp->pgout = pgout; 110 mp->pgcookie = pgcookie; 111} |
135 | 112 |
136/* | 113/* |
137 * MPOOL_NEW -- get a new page 138 * 139 * Parameters: 140 * mp: mpool cookie 141 * pgnoadddr: place to store new page number 142 * Returns: 143 * RET_ERROR, RET_SUCCESS | 114 * mpool_new -- 115 * Get a new page of memory. |
144 */ 145void * 146mpool_new(mp, pgnoaddr) 147 MPOOL *mp; 148 pgno_t *pgnoaddr; 149{ | 116 */ 117void * 118mpool_new(mp, pgnoaddr) 119 MPOOL *mp; 120 pgno_t *pgnoaddr; 121{ |
150 BKT *b; 151 BKTHDR *hp; | 122 struct _hqh *head; 123 BKT *bp; |
152 | 124 |
125 if (mp->npages == MAX_PAGE_NUMBER) { 126 (void)fprintf(stderr, "mpool_new: page allocation overflow.\n"); 127 abort(); 128 } |
|
153#ifdef STATISTICS 154 ++mp->pagenew; 155#endif 156 /* | 129#ifdef STATISTICS 130 ++mp->pagenew; 131#endif 132 /* |
157 * Get a BKT from the cache. Assign a new page number, attach it to 158 * the hash and lru chains and return. | 133 * Get a BKT from the cache. Assign a new page number, attach 134 * it to the head of the hash chain, the tail of the lru chain, 135 * and return. |
159 */ | 136 */ |
160 if ((b = mpool_bkt(mp)) == NULL) | 137 if ((bp = mpool_bkt(mp)) == NULL) |
161 return (NULL); | 138 return (NULL); |
162 *pgnoaddr = b->pgno = mp->npages++; 163 b->flags = MPOOL_PINNED; 164 inshash(b, b->pgno); 165 inschain(b, &mp->lru); 166 return (b->page); | 139 *pgnoaddr = bp->pgno = mp->npages++; 140 bp->flags = MPOOL_PINNED; 141 142 head = &mp->hqh[HASHKEY(bp->pgno)]; 143 CIRCLEQ_INSERT_HEAD(head, bp, hq); 144 CIRCLEQ_INSERT_TAIL(&mp->lqh, bp, q); 145 return (bp->page); |
167} 168 169/* | 146} 147 148/* |
170 * MPOOL_GET -- get a page from the pool 171 * 172 * Parameters: 173 * mp: mpool cookie 174 * pgno: page number 175 * flags: not used 176 * 177 * Returns: 178 * RET_ERROR, RET_SUCCESS | 149 * mpool_get 150 * Get a page. |
179 */ 180void * 181mpool_get(mp, pgno, flags) 182 MPOOL *mp; 183 pgno_t pgno; | 151 */ 152void * 153mpool_get(mp, pgno, flags) 154 MPOOL *mp; 155 pgno_t pgno; |
184 u_int flags; /* XXX not used? */ | 156 u_int flags; /* XXX not used? */ |
185{ | 157{ |
186 BKT *b; 187 BKTHDR *hp; | 158 struct _hqh *head; 159 BKT *bp; |
188 off_t off; 189 int nr; 190 | 160 off_t off; 161 int nr; 162 |
191 /* 192 * If asking for a specific page that is already in the cache, find 193 * it and return it. 194 */ 195 if (b = mpool_look(mp, pgno)) { | 163 /* Check for attempt to retrieve a non-existent page. */ 164 if (pgno >= mp->npages) { 165 errno = EINVAL; 166 return (NULL); 167 } 168 |
196#ifdef STATISTICS | 169#ifdef STATISTICS |
197 ++mp->pageget; | 170 ++mp->pageget; |
198#endif | 171#endif |
172 173 /* Check for a page that is cached. */ 174 if ((bp = mpool_look(mp, pgno)) != NULL) { |
|
199#ifdef DEBUG | 175#ifdef DEBUG |
200 if (b->flags & MPOOL_PINNED) 201 __mpoolerr("mpool_get: page %d already pinned", 202 b->pgno); | 176 if (bp->flags & MPOOL_PINNED) { 177 (void)fprintf(stderr, 178 "mpool_get: page %d already pinned\n", bp->pgno); 179 abort(); 180 } |
203#endif | 181#endif |
204 rmchain(b); 205 inschain(b, &mp->lru); 206 b->flags |= MPOOL_PINNED; 207 return (b->page); 208 } | 182 /* 183 * Move the page to the head of the hash chain and the tail 184 * of the lru chain. 185 */ 186 head = &mp->hqh[HASHKEY(bp->pgno)]; 187 CIRCLEQ_REMOVE(head, bp, hq); 188 CIRCLEQ_INSERT_HEAD(head, bp, hq); 189 CIRCLEQ_REMOVE(&mp->lqh, bp, q); 190 CIRCLEQ_INSERT_TAIL(&mp->lqh, bp, q); |
209 | 191 |
210 /* Not allowed to retrieve a non-existent page. */ 211 if (pgno >= mp->npages) { 212 errno = EINVAL; 213 return (NULL); | 192 /* Return a pinned page. */ 193 bp->flags |= MPOOL_PINNED; 194 return (bp->page); |
214 } 215 216 /* Get a page from the cache. */ | 195 } 196 197 /* Get a page from the cache. */ |
217 if ((b = mpool_bkt(mp)) == NULL) | 198 if ((bp = mpool_bkt(mp)) == NULL) |
218 return (NULL); | 199 return (NULL); |
219 b->pgno = pgno; 220 b->flags = MPOOL_PINNED; | |
221 | 200 |
201 /* Read in the contents. */ |
|
222#ifdef STATISTICS 223 ++mp->pageread; 224#endif | 202#ifdef STATISTICS 203 ++mp->pageread; 204#endif |
225 /* Read in the contents. */ | |
226 off = mp->pagesize * pgno; 227 if (lseek(mp->fd, off, SEEK_SET) != off) 228 return (NULL); | 205 off = mp->pagesize * pgno; 206 if (lseek(mp->fd, off, SEEK_SET) != off) 207 return (NULL); |
229 if ((nr = read(mp->fd, b->page, mp->pagesize)) != mp->pagesize) { | 208 if ((nr = read(mp->fd, bp->page, mp->pagesize)) != mp->pagesize) { |
230 if (nr >= 0) 231 errno = EFTYPE; 232 return (NULL); 233 } | 209 if (nr >= 0) 210 errno = EFTYPE; 211 return (NULL); 212 } |
234 if (mp->pgin) 235 (mp->pgin)(mp->pgcookie, b->pgno, b->page); | |
236 | 213 |
237 inshash(b, b->pgno); 238 inschain(b, &mp->lru); 239#ifdef STATISTICS 240 ++mp->pageget; 241#endif 242 return (b->page); | 214 /* Set the page number, pin the page. */ 215 bp->pgno = pgno; 216 bp->flags = MPOOL_PINNED; 217 218 /* 219 * Add the page to the head of the hash chain and the tail 220 * of the lru chain. 221 */ 222 head = &mp->hqh[HASHKEY(bp->pgno)]; 223 CIRCLEQ_INSERT_HEAD(head, bp, hq); 224 CIRCLEQ_INSERT_TAIL(&mp->lqh, bp, q); 225 226 /* Run through the user's filter. */ 227 if (mp->pgin != NULL) 228 (mp->pgin)(mp->pgcookie, bp->pgno, bp->page); 229 230 return (bp->page); |
243} 244 245/* | 231} 232 233/* |
246 * MPOOL_PUT -- return a page to the pool 247 * 248 * Parameters: 249 * mp: mpool cookie 250 * page: page pointer 251 * pgno: page number 252 * 253 * Returns: 254 * RET_ERROR, RET_SUCCESS | 234 * mpool_put 235 * Return a page. |
255 */ 256int 257mpool_put(mp, page, flags) 258 MPOOL *mp; 259 void *page; 260 u_int flags; 261{ | 236 */ 237int 238mpool_put(mp, page, flags) 239 MPOOL *mp; 240 void *page; 241 u_int flags; 242{ |
262 BKT *baddr; 263#ifdef DEBUG 264 BKT *b; 265#endif | 243 BKT *bp; |
266 267#ifdef STATISTICS 268 ++mp->pageput; 269#endif | 244 245#ifdef STATISTICS 246 ++mp->pageput; 247#endif |
270 baddr = (BKT *)((char *)page - sizeof(BKT)); | 248 bp = (BKT *)((char *)page - sizeof(BKT)); |
271#ifdef DEBUG | 249#ifdef DEBUG |
272 if (!(baddr->flags & MPOOL_PINNED)) 273 __mpoolerr("mpool_put: page %d not pinned", b->pgno); 274 for (b = mp->lru.cnext; b != (BKT *)&mp->lru; b = b->cnext) { 275 if (b == (BKT *)&mp->lru) 276 __mpoolerr("mpool_put: %0x: bad address", baddr); 277 if (b == baddr) 278 break; | 250 if (!(bp->flags & MPOOL_PINNED)) { 251 (void)fprintf(stderr, 252 "mpool_put: page %d not pinned\n", bp->pgno); 253 abort(); |
279 } 280#endif | 254 } 255#endif |
281 baddr->flags &= ~MPOOL_PINNED; 282 baddr->flags |= flags & MPOOL_DIRTY; | 256 bp->flags &= ~MPOOL_PINNED; 257 bp->flags |= flags & MPOOL_DIRTY; |
283 return (RET_SUCCESS); 284} 285 286/* | 258 return (RET_SUCCESS); 259} 260 261/* |
287 * MPOOL_CLOSE -- close the buffer pool 288 * 289 * Parameters: 290 * mp: mpool cookie 291 * 292 * Returns: 293 * RET_ERROR, RET_SUCCESS | 262 * mpool_close 263 * Close the buffer pool. |
294 */ 295int 296mpool_close(mp) 297 MPOOL *mp; 298{ | 264 */ 265int 266mpool_close(mp) 267 MPOOL *mp; 268{ |
299 BKT *b, *next; | 269 BKT *bp; |
300 301 /* Free up any space allocated to the lru pages. */ | 270 271 /* Free up any space allocated to the lru pages. */ |
302 for (b = mp->lru.cprev; b != (BKT *)&mp->lru; b = next) { 303 next = b->cprev; 304 free(b); | 272 while ((bp = mp->lqh.cqh_first) != (void *)&mp->lqh) { 273 CIRCLEQ_REMOVE(&mp->lqh, mp->lqh.cqh_first, q); 274 free(bp); |
305 } | 275 } |
276 277 /* Free the MPOOL cookie. */ |
|
306 free(mp); 307 return (RET_SUCCESS); 308} 309 310/* | 278 free(mp); 279 return (RET_SUCCESS); 280} 281 282/* |
311 * MPOOL_SYNC -- sync the file to disk. 312 * 313 * Parameters: 314 * mp: mpool cookie 315 * 316 * Returns: 317 * RET_ERROR, RET_SUCCESS | 283 * mpool_sync 284 * Sync the pool to disk. |
318 */ 319int 320mpool_sync(mp) 321 MPOOL *mp; 322{ | 285 */ 286int 287mpool_sync(mp) 288 MPOOL *mp; 289{ |
323 BKT *b; | 290 BKT *bp; |
324 | 291 |
325 for (b = mp->lru.cprev; b != (BKT *)&mp->lru; b = b->cprev) 326 if (b->flags & MPOOL_DIRTY && mpool_write(mp, b) == RET_ERROR) | 292 /* Walk the lru chain, flushing any dirty pages to disk. */ 293 for (bp = mp->lqh.cqh_first; 294 bp != (void *)&mp->lqh; bp = bp->q.cqe_next) 295 if (bp->flags & MPOOL_DIRTY && 296 mpool_write(mp, bp) == RET_ERROR) |
327 return (RET_ERROR); | 297 return (RET_ERROR); |
298 299 /* Sync the file descriptor. */ |
|
328 return (fsync(mp->fd) ? RET_ERROR : RET_SUCCESS); 329} 330 331/* | 300 return (fsync(mp->fd) ? RET_ERROR : RET_SUCCESS); 301} 302 303/* |
332 * MPOOL_BKT -- get/create a BKT from the cache 333 * 334 * Parameters: 335 * mp: mpool cookie 336 * 337 * Returns: 338 * NULL on failure and a pointer to the BKT on success | 304 * mpool_bkt 305 * Get a page from the cache (or create one). |
339 */ 340static BKT * 341mpool_bkt(mp) 342 MPOOL *mp; 343{ | 306 */ 307static BKT * 308mpool_bkt(mp) 309 MPOOL *mp; 310{ |
344 BKT *b; | 311 struct _hqh *head; 312 BKT *bp; |
345 | 313 |
314 /* If under the max cached, always create a new page. */ |
|
346 if (mp->curcache < mp->maxcache) 347 goto new; 348 349 /* | 315 if (mp->curcache < mp->maxcache) 316 goto new; 317 318 /* |
350 * If the cache is maxxed out, search the lru list for a buffer we 351 * can flush. If we find one, write it if necessary and take it off 352 * any lists. If we don't find anything we grow the cache anyway. | 319 * If the cache is max'd out, walk the lru list for a buffer we 320 * can flush. If we find one, write it (if necessary) and take it 321 * off any lists. If we don't find anything we grow the cache anyway. |
353 * The cache never shrinks. 354 */ | 322 * The cache never shrinks. 323 */ |
355 for (b = mp->lru.cprev; b != (BKT *)&mp->lru; b = b->cprev) 356 if (!(b->flags & MPOOL_PINNED)) { 357 if (b->flags & MPOOL_DIRTY && 358 mpool_write(mp, b) == RET_ERROR) | 324 for (bp = mp->lqh.cqh_first; 325 bp != (void *)&mp->lqh; bp = bp->q.cqe_next) 326 if (!(bp->flags & MPOOL_PINNED)) { 327 /* Flush if dirty. */ 328 if (bp->flags & MPOOL_DIRTY && 329 mpool_write(mp, bp) == RET_ERROR) |
359 return (NULL); | 330 return (NULL); |
360 rmhash(b); 361 rmchain(b); | |
362#ifdef STATISTICS 363 ++mp->pageflush; 364#endif | 331#ifdef STATISTICS 332 ++mp->pageflush; 333#endif |
334 /* Remove from the hash and lru queues. */ 335 head = &mp->hqh[HASHKEY(bp->pgno)]; 336 CIRCLEQ_REMOVE(head, bp, hq); 337 CIRCLEQ_REMOVE(&mp->lqh, bp, q); |
|
365#ifdef DEBUG | 338#ifdef DEBUG |
366 { 367 void *spage; 368 spage = b->page; 369 memset(b, 0xff, sizeof(BKT) + mp->pagesize); 370 b->page = spage; | 339 { void *spage; 340 spage = bp->page; 341 memset(bp, 0xff, sizeof(BKT) + mp->pagesize); 342 bp->page = spage; |
371 } 372#endif | 343 } 344#endif |
373 return (b); | 345 return (bp); |
374 } 375 | 346 } 347 |
376new: if ((b = (BKT *)malloc(sizeof(BKT) + mp->pagesize)) == NULL) | 348new: if ((bp = (BKT *)malloc(sizeof(BKT) + mp->pagesize)) == NULL) |
377 return (NULL); 378#ifdef STATISTICS 379 ++mp->pagealloc; 380#endif | 349 return (NULL); 350#ifdef STATISTICS 351 ++mp->pagealloc; 352#endif |
381#ifdef DEBUG 382 memset(b, 0xff, sizeof(BKT) + mp->pagesize); | 353#if defined(DEBUG) || defined(PURIFY) 354 memset(bp, 0xff, sizeof(BKT) + mp->pagesize); |
383#endif | 355#endif |
384 b->page = (char *)b + sizeof(BKT); | 356 bp->page = (char *)bp + sizeof(BKT); |
385 ++mp->curcache; | 357 ++mp->curcache; |
386 return (b); | 358 return (bp); |
387} 388 389/* | 359} 360 361/* |
390 * MPOOL_WRITE -- sync a page to disk 391 * 392 * Parameters: 393 * mp: mpool cookie 394 * 395 * Returns: 396 * RET_ERROR, RET_SUCCESS | 362 * mpool_write 363 * Write a page to disk. |
397 */ 398static int | 364 */ 365static int |
399mpool_write(mp, b) | 366mpool_write(mp, bp) |
400 MPOOL *mp; | 367 MPOOL *mp; |
401 BKT *b; | 368 BKT *bp; |
402{ 403 off_t off; 404 | 369{ 370 off_t off; 371 |
405 if (mp->pgout) 406 (mp->pgout)(mp->pgcookie, b->pgno, b->page); 407 | |
408#ifdef STATISTICS 409 ++mp->pagewrite; 410#endif | 372#ifdef STATISTICS 373 ++mp->pagewrite; 374#endif |
411 off = mp->pagesize * b->pgno; | 375 376 /* Run through the user's filter. */ 377 if (mp->pgout) 378 (mp->pgout)(mp->pgcookie, bp->pgno, bp->page); 379 380 off = mp->pagesize * bp->pgno; |
412 if (lseek(mp->fd, off, SEEK_SET) != off) 413 return (RET_ERROR); | 381 if (lseek(mp->fd, off, SEEK_SET) != off) 382 return (RET_ERROR); |
414 if (write(mp->fd, b->page, mp->pagesize) != mp->pagesize) | 383 if (write(mp->fd, bp->page, mp->pagesize) != mp->pagesize) |
415 return (RET_ERROR); | 384 return (RET_ERROR); |
416 b->flags &= ~MPOOL_DIRTY; | 385 386 bp->flags &= ~MPOOL_DIRTY; |
417 return (RET_SUCCESS); 418} 419 420/* | 387 return (RET_SUCCESS); 388} 389 390/* |
421 * MPOOL_LOOK -- lookup a page 422 * 423 * Parameters: 424 * mp: mpool cookie 425 * pgno: page number 426 * 427 * Returns: 428 * NULL on failure and a pointer to the BKT on success | 391 * mpool_look 392 * Lookup a page in the cache. |
429 */ 430static BKT * 431mpool_look(mp, pgno) 432 MPOOL *mp; 433 pgno_t pgno; 434{ | 393 */ 394static BKT * 395mpool_look(mp, pgno) 396 MPOOL *mp; 397 pgno_t pgno; 398{ |
435 register BKT *b; 436 register BKTHDR *tb; | 399 struct _hqh *head; 400 BKT *bp; |
437 | 401 |
438 /* XXX 439 * If find the buffer, put it first on the hash chain so can 440 * find it again quickly. 441 */ 442 tb = &mp->hashtable[HASHKEY(pgno)]; 443 for (b = tb->hnext; b != (BKT *)tb; b = b->hnext) 444 if (b->pgno == pgno) { | 402 head = &mp->hqh[HASHKEY(pgno)]; 403 for (bp = head->cqh_first; bp != (void *)head; bp = bp->hq.cqe_next) 404 if (bp->pgno == pgno) { |
445#ifdef STATISTICS 446 ++mp->cachehit; 447#endif | 405#ifdef STATISTICS 406 ++mp->cachehit; 407#endif |
448 return (b); | 408 return (bp); |
449 } 450#ifdef STATISTICS 451 ++mp->cachemiss; 452#endif 453 return (NULL); 454} 455 456#ifdef STATISTICS 457/* | 409 } 410#ifdef STATISTICS 411 ++mp->cachemiss; 412#endif 413 return (NULL); 414} 415 416#ifdef STATISTICS 417/* |
458 * MPOOL_STAT -- cache statistics 459 * 460 * Parameters: 461 * mp: mpool cookie | 418 * mpool_stat 419 * Print out cache statistics. |
462 */ 463void 464mpool_stat(mp) 465 MPOOL *mp; 466{ | 420 */ 421void 422mpool_stat(mp) 423 MPOOL *mp; 424{ |
467 BKT *b; | 425 BKT *bp; |
468 int cnt; 469 char *sep; 470 471 (void)fprintf(stderr, "%lu pages in the file\n", mp->npages); 472 (void)fprintf(stderr, 473 "page size %lu, cacheing %lu pages of %lu page max cache\n", 474 mp->pagesize, mp->curcache, mp->maxcache); 475 (void)fprintf(stderr, "%lu page puts, %lu page gets, %lu page new\n", 476 mp->pageput, mp->pageget, mp->pagenew); 477 (void)fprintf(stderr, "%lu page allocs, %lu page flushes\n", 478 mp->pagealloc, mp->pageflush); 479 if (mp->cachehit + mp->cachemiss) 480 (void)fprintf(stderr, | 426 int cnt; 427 char *sep; 428 429 (void)fprintf(stderr, "%lu pages in the file\n", mp->npages); 430 (void)fprintf(stderr, 431 "page size %lu, cacheing %lu pages of %lu page max cache\n", 432 mp->pagesize, mp->curcache, mp->maxcache); 433 (void)fprintf(stderr, "%lu page puts, %lu page gets, %lu page new\n", 434 mp->pageput, mp->pageget, mp->pagenew); 435 (void)fprintf(stderr, "%lu page allocs, %lu page flushes\n", 436 mp->pagealloc, mp->pageflush); 437 if (mp->cachehit + mp->cachemiss) 438 (void)fprintf(stderr, |
481 "%.0f%% cache hit rate (%lu hits, %lu misses)\n", | 439 "%.0f%% cache hit rate (%lu hits, %lu misses)\n", |
482 ((double)mp->cachehit / (mp->cachehit + mp->cachemiss)) 483 * 100, mp->cachehit, mp->cachemiss); 484 (void)fprintf(stderr, "%lu page reads, %lu page writes\n", 485 mp->pageread, mp->pagewrite); 486 487 sep = ""; 488 cnt = 0; | 440 ((double)mp->cachehit / (mp->cachehit + mp->cachemiss)) 441 * 100, mp->cachehit, mp->cachemiss); 442 (void)fprintf(stderr, "%lu page reads, %lu page writes\n", 443 mp->pageread, mp->pagewrite); 444 445 sep = ""; 446 cnt = 0; |
489 for (b = mp->lru.cnext; b != (BKT *)&mp->lru; b = b->cnext) { 490 (void)fprintf(stderr, "%s%d", sep, b->pgno); 491 if (b->flags & MPOOL_DIRTY) | 447 for (bp = mp->lqh.cqh_first; 448 bp != (void *)&mp->lqh; bp = bp->q.cqe_next) { 449 (void)fprintf(stderr, "%s%d", sep, bp->pgno); 450 if (bp->flags & MPOOL_DIRTY) |
492 (void)fprintf(stderr, "d"); | 451 (void)fprintf(stderr, "d"); |
493 if (b->flags & MPOOL_PINNED) | 452 if (bp->flags & MPOOL_PINNED) |
494 (void)fprintf(stderr, "P"); 495 if (++cnt == 10) { 496 sep = "\n"; 497 cnt = 0; 498 } else 499 sep = ", "; | 453 (void)fprintf(stderr, "P"); 454 if (++cnt == 10) { 455 sep = "\n"; 456 cnt = 0; 457 } else 458 sep = ", "; |
500 | 459 |
501 } 502 (void)fprintf(stderr, "\n"); 503} 504#endif | 460 } 461 (void)fprintf(stderr, "\n"); 462} 463#endif |
505 506#ifdef DEBUG 507#if __STDC__ 508#include <stdarg.h> 509#else 510#include <varargs.h> 511#endif 512 513static void 514#if __STDC__ 515__mpoolerr(const char *fmt, ...) 516#else 517__mpoolerr(fmt, va_alist) 518 char *fmt; 519 va_dcl 520#endif 521{ 522 va_list ap; 523#if __STDC__ 524 va_start(ap, fmt); 525#else 526 va_start(ap); 527#endif 528 (void)vfprintf(stderr, fmt, ap); 529 va_end(ap); 530 (void)fprintf(stderr, "\n"); 531 abort(); 532 /* NOTREACHED */ 533} 534#endif | |