1*2639ae9bSBen Gras /* $NetBSD: hash_buf.c,v 1.18 2009/04/23 22:09:23 christos Exp $ */ 2*2639ae9bSBen Gras 3*2639ae9bSBen Gras /*- 4*2639ae9bSBen Gras * Copyright (c) 1990, 1993, 1994 5*2639ae9bSBen Gras * The Regents of the University of California. All rights reserved. 6*2639ae9bSBen Gras * 7*2639ae9bSBen Gras * This code is derived from software contributed to Berkeley by 8*2639ae9bSBen Gras * Margo Seltzer. 9*2639ae9bSBen Gras * 10*2639ae9bSBen Gras * Redistribution and use in source and binary forms, with or without 11*2639ae9bSBen Gras * modification, are permitted provided that the following conditions 12*2639ae9bSBen Gras * are met: 13*2639ae9bSBen Gras * 1. Redistributions of source code must retain the above copyright 14*2639ae9bSBen Gras * notice, this list of conditions and the following disclaimer. 15*2639ae9bSBen Gras * 2. Redistributions in binary form must reproduce the above copyright 16*2639ae9bSBen Gras * notice, this list of conditions and the following disclaimer in the 17*2639ae9bSBen Gras * documentation and/or other materials provided with the distribution. 18*2639ae9bSBen Gras * 3. Neither the name of the University nor the names of its contributors 19*2639ae9bSBen Gras * may be used to endorse or promote products derived from this software 20*2639ae9bSBen Gras * without specific prior written permission. 21*2639ae9bSBen Gras * 22*2639ae9bSBen Gras * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23*2639ae9bSBen Gras * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24*2639ae9bSBen Gras * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25*2639ae9bSBen Gras * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26*2639ae9bSBen Gras * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27*2639ae9bSBen Gras * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28*2639ae9bSBen Gras * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29*2639ae9bSBen Gras * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30*2639ae9bSBen Gras * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31*2639ae9bSBen Gras * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32*2639ae9bSBen Gras * SUCH DAMAGE. 33*2639ae9bSBen Gras */ 34*2639ae9bSBen Gras 35*2639ae9bSBen Gras #if HAVE_NBTOOL_CONFIG_H 36*2639ae9bSBen Gras #include "nbtool_config.h" 37*2639ae9bSBen Gras #endif 38*2639ae9bSBen Gras 39*2639ae9bSBen Gras #include <sys/cdefs.h> 40*2639ae9bSBen Gras #ifndef __minix 41*2639ae9bSBen Gras __RCSID("$NetBSD: hash_buf.c,v 1.18 2009/04/23 22:09:23 christos Exp $"); 42*2639ae9bSBen Gras #endif 43*2639ae9bSBen Gras 44*2639ae9bSBen Gras /* 45*2639ae9bSBen Gras * PACKAGE: hash 46*2639ae9bSBen Gras * 47*2639ae9bSBen Gras * DESCRIPTION: 48*2639ae9bSBen Gras * Contains buffer management 49*2639ae9bSBen Gras * 50*2639ae9bSBen Gras * ROUTINES: 51*2639ae9bSBen Gras * External 52*2639ae9bSBen Gras * __buf_init 53*2639ae9bSBen Gras * __get_buf 54*2639ae9bSBen Gras * __buf_free 55*2639ae9bSBen Gras * __reclaim_buf 56*2639ae9bSBen Gras * Internal 57*2639ae9bSBen Gras * newbuf 58*2639ae9bSBen Gras */ 59*2639ae9bSBen Gras 60*2639ae9bSBen Gras #include <sys/param.h> 61*2639ae9bSBen Gras 62*2639ae9bSBen Gras #include <errno.h> 63*2639ae9bSBen Gras #include <stddef.h> 64*2639ae9bSBen Gras #include <stdio.h> 65*2639ae9bSBen Gras #include <stdlib.h> 66*2639ae9bSBen Gras #include <string.h> 67*2639ae9bSBen Gras #include <assert.h> 68*2639ae9bSBen Gras 69*2639ae9bSBen Gras #include <db.h> 70*2639ae9bSBen Gras #include "hash.h" 71*2639ae9bSBen Gras #include "page.h" 72*2639ae9bSBen Gras #include "extern.h" 73*2639ae9bSBen Gras 74*2639ae9bSBen Gras static BUFHEAD *newbuf(HTAB *, uint32_t, BUFHEAD *); 75*2639ae9bSBen Gras 76*2639ae9bSBen Gras /* Unlink B from its place in the lru */ 77*2639ae9bSBen Gras #define BUF_REMOVE(B) { \ 78*2639ae9bSBen Gras (B)->prev->next = (B)->next; \ 79*2639ae9bSBen Gras (B)->next->prev = (B)->prev; \ 80*2639ae9bSBen Gras } 81*2639ae9bSBen Gras 82*2639ae9bSBen Gras /* Insert B after P */ 83*2639ae9bSBen Gras #define BUF_INSERT(B, P) { \ 84*2639ae9bSBen Gras (B)->next = (P)->next; \ 85*2639ae9bSBen Gras (B)->prev = (P); \ 86*2639ae9bSBen Gras (P)->next = (B); \ 87*2639ae9bSBen Gras (B)->next->prev = (B); \ 88*2639ae9bSBen Gras } 89*2639ae9bSBen Gras 90*2639ae9bSBen Gras #define MRU hashp->bufhead.next 91*2639ae9bSBen Gras #define LRU hashp->bufhead.prev 92*2639ae9bSBen Gras 93*2639ae9bSBen Gras #define MRU_INSERT(B) BUF_INSERT((B), &hashp->bufhead) 94*2639ae9bSBen Gras #define LRU_INSERT(B) BUF_INSERT((B), LRU) 95*2639ae9bSBen Gras 96*2639ae9bSBen Gras #ifndef _DIAGASSERT 97*2639ae9bSBen Gras #define _DIAGASSERT assert 98*2639ae9bSBen Gras #endif 99*2639ae9bSBen Gras 100*2639ae9bSBen Gras #define MAX(a, b) ((a) > (b) ? (a) : (b)) 101*2639ae9bSBen Gras #define MIN(a, b) ((a) < (b) ? (a) : (b)) 102*2639ae9bSBen Gras /* 103*2639ae9bSBen Gras * We are looking for a buffer with address "addr". If prev_bp is NULL, then 104*2639ae9bSBen Gras * address is a bucket index. If prev_bp is not NULL, then it points to the 105*2639ae9bSBen Gras * page previous to an overflow page that we are trying to find. 106*2639ae9bSBen Gras * 107*2639ae9bSBen Gras * CAVEAT: The buffer header accessed via prev_bp's ovfl field may no longer 108*2639ae9bSBen Gras * be valid. Therefore, you must always verify that its address matches the 109*2639ae9bSBen Gras * address you are seeking. 110*2639ae9bSBen Gras */ 111*2639ae9bSBen Gras BUFHEAD * 112*2639ae9bSBen Gras __get_buf( 113*2639ae9bSBen Gras HTAB *hashp, 114*2639ae9bSBen Gras uint32_t addr, 115*2639ae9bSBen Gras BUFHEAD *prev_bp, 116*2639ae9bSBen Gras int newpage /* If prev_bp set, indicates a new overflow page. */ 117*2639ae9bSBen Gras ) 118*2639ae9bSBen Gras { 119*2639ae9bSBen Gras BUFHEAD *bp; 120*2639ae9bSBen Gras uint32_t is_disk_mask; 121*2639ae9bSBen Gras int is_disk, segment_ndx = 0; /* pacify gcc */ 122*2639ae9bSBen Gras SEGMENT segp = NULL; /* pacify gcc */ 123*2639ae9bSBen Gras 124*2639ae9bSBen Gras is_disk = 0; 125*2639ae9bSBen Gras is_disk_mask = 0; 126*2639ae9bSBen Gras if (prev_bp) { 127*2639ae9bSBen Gras bp = prev_bp->ovfl; 128*2639ae9bSBen Gras if (!bp || (bp->addr != addr)) 129*2639ae9bSBen Gras bp = NULL; 130*2639ae9bSBen Gras if (!newpage) 131*2639ae9bSBen Gras is_disk = BUF_DISK; 132*2639ae9bSBen Gras } else { 133*2639ae9bSBen Gras /* Grab buffer out of directory */ 134*2639ae9bSBen Gras segment_ndx = addr & (hashp->SGSIZE - 1); 135*2639ae9bSBen Gras 136*2639ae9bSBen Gras /* valid segment ensured by __call_hash() */ 137*2639ae9bSBen Gras segp = hashp->dir[addr >> hashp->SSHIFT]; 138*2639ae9bSBen Gras _DIAGASSERT(segp != NULL); 139*2639ae9bSBen Gras bp = PTROF(segp[segment_ndx]); 140*2639ae9bSBen Gras is_disk_mask = ISDISK(segp[segment_ndx]); 141*2639ae9bSBen Gras is_disk = is_disk_mask || !hashp->new_file; 142*2639ae9bSBen Gras } 143*2639ae9bSBen Gras 144*2639ae9bSBen Gras if (!bp) { 145*2639ae9bSBen Gras bp = newbuf(hashp, addr, prev_bp); 146*2639ae9bSBen Gras if (!bp || 147*2639ae9bSBen Gras __get_page(hashp, bp->page, addr, !prev_bp, is_disk, 0)) 148*2639ae9bSBen Gras return (NULL); 149*2639ae9bSBen Gras if (!prev_bp) 150*2639ae9bSBen Gras segp[segment_ndx] = 151*2639ae9bSBen Gras (BUFHEAD *)(void *)((u_long)bp | is_disk_mask); 152*2639ae9bSBen Gras } else { 153*2639ae9bSBen Gras BUF_REMOVE(bp); 154*2639ae9bSBen Gras MRU_INSERT(bp); 155*2639ae9bSBen Gras } 156*2639ae9bSBen Gras return (bp); 157*2639ae9bSBen Gras } 158*2639ae9bSBen Gras 159*2639ae9bSBen Gras /* 160*2639ae9bSBen Gras * We need a buffer for this page. Either allocate one, or evict a resident 161*2639ae9bSBen Gras * one (if we have as many buffers as we're allowed) and put this one in. 162*2639ae9bSBen Gras * 163*2639ae9bSBen Gras * If newbuf finds an error (returning NULL), it also sets errno. 164*2639ae9bSBen Gras */ 165*2639ae9bSBen Gras static BUFHEAD * 166*2639ae9bSBen Gras newbuf(HTAB *hashp, uint32_t addr, BUFHEAD *prev_bp) 167*2639ae9bSBen Gras { 168*2639ae9bSBen Gras BUFHEAD *bp; /* The buffer we're going to use */ 169*2639ae9bSBen Gras BUFHEAD *xbp; /* Temp pointer */ 170*2639ae9bSBen Gras BUFHEAD *next_xbp; 171*2639ae9bSBen Gras SEGMENT segp; 172*2639ae9bSBen Gras int segment_ndx; 173*2639ae9bSBen Gras uint16_t oaddr, *shortp; 174*2639ae9bSBen Gras 175*2639ae9bSBen Gras oaddr = 0; 176*2639ae9bSBen Gras bp = LRU; 177*2639ae9bSBen Gras /* 178*2639ae9bSBen Gras * If LRU buffer is pinned, the buffer pool is too small. We need to 179*2639ae9bSBen Gras * allocate more buffers. 180*2639ae9bSBen Gras */ 181*2639ae9bSBen Gras if (hashp->nbufs || (bp->flags & BUF_PIN)) { 182*2639ae9bSBen Gras /* Allocate a new one */ 183*2639ae9bSBen Gras if ((bp = calloc(1, sizeof(BUFHEAD))) == NULL) 184*2639ae9bSBen Gras return (NULL); 185*2639ae9bSBen Gras if ((bp->page = calloc(1, (size_t)hashp->BSIZE)) == NULL) { 186*2639ae9bSBen Gras free(bp); 187*2639ae9bSBen Gras return (NULL); 188*2639ae9bSBen Gras } 189*2639ae9bSBen Gras if (hashp->nbufs) 190*2639ae9bSBen Gras hashp->nbufs--; 191*2639ae9bSBen Gras } else { 192*2639ae9bSBen Gras /* Kick someone out */ 193*2639ae9bSBen Gras BUF_REMOVE(bp); 194*2639ae9bSBen Gras /* 195*2639ae9bSBen Gras * If this is an overflow page with addr 0, it's already been 196*2639ae9bSBen Gras * flushed back in an overflow chain and initialized. 197*2639ae9bSBen Gras */ 198*2639ae9bSBen Gras if ((bp->addr != 0) || (bp->flags & BUF_BUCKET)) { 199*2639ae9bSBen Gras /* 200*2639ae9bSBen Gras * Set oaddr before __put_page so that you get it 201*2639ae9bSBen Gras * before bytes are swapped. 202*2639ae9bSBen Gras */ 203*2639ae9bSBen Gras shortp = (uint16_t *)(void *)bp->page; 204*2639ae9bSBen Gras if (shortp[0]) 205*2639ae9bSBen Gras oaddr = shortp[shortp[0] - 1]; 206*2639ae9bSBen Gras if ((bp->flags & BUF_MOD) && __put_page(hashp, bp->page, 207*2639ae9bSBen Gras bp->addr, (int)IS_BUCKET(bp->flags), 0)) 208*2639ae9bSBen Gras return (NULL); 209*2639ae9bSBen Gras /* 210*2639ae9bSBen Gras * Update the pointer to this page (i.e. invalidate it). 211*2639ae9bSBen Gras * 212*2639ae9bSBen Gras * If this is a new file (i.e. we created it at open 213*2639ae9bSBen Gras * time), make sure that we mark pages which have been 214*2639ae9bSBen Gras * written to disk so we retrieve them from disk later, 215*2639ae9bSBen Gras * rather than allocating new pages. 216*2639ae9bSBen Gras */ 217*2639ae9bSBen Gras if (IS_BUCKET(bp->flags)) { 218*2639ae9bSBen Gras segment_ndx = bp->addr & (hashp->SGSIZE - 1); 219*2639ae9bSBen Gras segp = hashp->dir[bp->addr >> hashp->SSHIFT]; 220*2639ae9bSBen Gras _DIAGASSERT(segp != NULL); 221*2639ae9bSBen Gras 222*2639ae9bSBen Gras if (hashp->new_file && 223*2639ae9bSBen Gras ((bp->flags & BUF_MOD) || 224*2639ae9bSBen Gras ISDISK(segp[segment_ndx]))) 225*2639ae9bSBen Gras segp[segment_ndx] = (BUFHEAD *)BUF_DISK; 226*2639ae9bSBen Gras else 227*2639ae9bSBen Gras segp[segment_ndx] = NULL; 228*2639ae9bSBen Gras } 229*2639ae9bSBen Gras /* 230*2639ae9bSBen Gras * Since overflow pages can only be access by means of 231*2639ae9bSBen Gras * their bucket, free overflow pages associated with 232*2639ae9bSBen Gras * this bucket. 233*2639ae9bSBen Gras */ 234*2639ae9bSBen Gras for (xbp = bp; xbp->ovfl;) { 235*2639ae9bSBen Gras next_xbp = xbp->ovfl; 236*2639ae9bSBen Gras xbp->ovfl = 0; 237*2639ae9bSBen Gras xbp = next_xbp; 238*2639ae9bSBen Gras 239*2639ae9bSBen Gras /* Check that ovfl pointer is up date. */ 240*2639ae9bSBen Gras if (IS_BUCKET(xbp->flags) || 241*2639ae9bSBen Gras (oaddr != xbp->addr)) 242*2639ae9bSBen Gras break; 243*2639ae9bSBen Gras 244*2639ae9bSBen Gras shortp = (uint16_t *)(void *)xbp->page; 245*2639ae9bSBen Gras if (shortp[0]) 246*2639ae9bSBen Gras /* set before __put_page */ 247*2639ae9bSBen Gras oaddr = shortp[shortp[0] - 1]; 248*2639ae9bSBen Gras if ((xbp->flags & BUF_MOD) && __put_page(hashp, 249*2639ae9bSBen Gras xbp->page, xbp->addr, 0, 0)) 250*2639ae9bSBen Gras return (NULL); 251*2639ae9bSBen Gras xbp->addr = 0; 252*2639ae9bSBen Gras xbp->flags = 0; 253*2639ae9bSBen Gras BUF_REMOVE(xbp); 254*2639ae9bSBen Gras LRU_INSERT(xbp); 255*2639ae9bSBen Gras } 256*2639ae9bSBen Gras } 257*2639ae9bSBen Gras } 258*2639ae9bSBen Gras 259*2639ae9bSBen Gras /* Now assign this buffer */ 260*2639ae9bSBen Gras bp->addr = addr; 261*2639ae9bSBen Gras #ifdef DEBUG1 262*2639ae9bSBen Gras (void)fprintf(stderr, "NEWBUF1: %d->ovfl was %d is now %d\n", 263*2639ae9bSBen Gras bp->addr, (bp->ovfl ? bp->ovfl->addr : 0), 0); 264*2639ae9bSBen Gras #endif 265*2639ae9bSBen Gras bp->ovfl = NULL; 266*2639ae9bSBen Gras if (prev_bp) { 267*2639ae9bSBen Gras /* 268*2639ae9bSBen Gras * If prev_bp is set, this is an overflow page, hook it in to 269*2639ae9bSBen Gras * the buffer overflow links. 270*2639ae9bSBen Gras */ 271*2639ae9bSBen Gras #ifdef DEBUG1 272*2639ae9bSBen Gras (void)fprintf(stderr, "NEWBUF2: %d->ovfl was %d is now %d\n", 273*2639ae9bSBen Gras prev_bp->addr, (prev_bp->ovfl ? prev_bp->ovfl->addr : 0), 274*2639ae9bSBen Gras (bp ? bp->addr : 0)); 275*2639ae9bSBen Gras #endif 276*2639ae9bSBen Gras prev_bp->ovfl = bp; 277*2639ae9bSBen Gras bp->flags = 0; 278*2639ae9bSBen Gras } else 279*2639ae9bSBen Gras bp->flags = BUF_BUCKET; 280*2639ae9bSBen Gras MRU_INSERT(bp); 281*2639ae9bSBen Gras return (bp); 282*2639ae9bSBen Gras } 283*2639ae9bSBen Gras 284*2639ae9bSBen Gras void 285*2639ae9bSBen Gras __buf_init(HTAB *hashp, u_int nbytes) 286*2639ae9bSBen Gras { 287*2639ae9bSBen Gras BUFHEAD *bfp; 288*2639ae9bSBen Gras int npages; 289*2639ae9bSBen Gras 290*2639ae9bSBen Gras bfp = &(hashp->bufhead); 291*2639ae9bSBen Gras npages = (unsigned int)(nbytes + hashp->BSIZE - 1) >> hashp->BSHIFT; 292*2639ae9bSBen Gras npages = MAX(npages, MIN_BUFFERS); 293*2639ae9bSBen Gras 294*2639ae9bSBen Gras hashp->nbufs = npages; 295*2639ae9bSBen Gras bfp->next = bfp; 296*2639ae9bSBen Gras bfp->prev = bfp; 297*2639ae9bSBen Gras /* 298*2639ae9bSBen Gras * This space is calloc'd so these are already null. 299*2639ae9bSBen Gras * 300*2639ae9bSBen Gras * bfp->ovfl = NULL; 301*2639ae9bSBen Gras * bfp->flags = 0; 302*2639ae9bSBen Gras * bfp->page = NULL; 303*2639ae9bSBen Gras * bfp->addr = 0; 304*2639ae9bSBen Gras */ 305*2639ae9bSBen Gras } 306*2639ae9bSBen Gras 307*2639ae9bSBen Gras int 308*2639ae9bSBen Gras __buf_free(HTAB *hashp, int do_free, int to_disk) 309*2639ae9bSBen Gras { 310*2639ae9bSBen Gras BUFHEAD *bp; 311*2639ae9bSBen Gras 312*2639ae9bSBen Gras /* Need to make sure that buffer manager has been initialized */ 313*2639ae9bSBen Gras if (!LRU) 314*2639ae9bSBen Gras return (0); 315*2639ae9bSBen Gras for (bp = LRU; bp != &hashp->bufhead;) { 316*2639ae9bSBen Gras /* Check that the buffer is valid */ 317*2639ae9bSBen Gras if (bp->addr || IS_BUCKET(bp->flags)) { 318*2639ae9bSBen Gras if (to_disk && (bp->flags & BUF_MOD) && 319*2639ae9bSBen Gras __put_page(hashp, bp->page, 320*2639ae9bSBen Gras bp->addr, IS_BUCKET(bp->flags), 0)) 321*2639ae9bSBen Gras return (-1); 322*2639ae9bSBen Gras } 323*2639ae9bSBen Gras /* Check if we are freeing stuff */ 324*2639ae9bSBen Gras if (do_free) { 325*2639ae9bSBen Gras if (bp->page) { 326*2639ae9bSBen Gras (void)memset(bp->page, 0, (size_t)hashp->BSIZE); 327*2639ae9bSBen Gras free(bp->page); 328*2639ae9bSBen Gras } 329*2639ae9bSBen Gras BUF_REMOVE(bp); 330*2639ae9bSBen Gras free(bp); 331*2639ae9bSBen Gras bp = LRU; 332*2639ae9bSBen Gras } else 333*2639ae9bSBen Gras bp = bp->prev; 334*2639ae9bSBen Gras } 335*2639ae9bSBen Gras return (0); 336*2639ae9bSBen Gras } 337*2639ae9bSBen Gras 338*2639ae9bSBen Gras void 339*2639ae9bSBen Gras __reclaim_buf(HTAB *hashp, BUFHEAD *bp) 340*2639ae9bSBen Gras { 341*2639ae9bSBen Gras bp->ovfl = 0; 342*2639ae9bSBen Gras bp->addr = 0; 343*2639ae9bSBen Gras bp->flags = 0; 344*2639ae9bSBen Gras BUF_REMOVE(bp); 345*2639ae9bSBen Gras LRU_INSERT(bp); 346*2639ae9bSBen Gras } 347