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 __RCSID("$NetBSD: hash_buf.c,v 1.18 2009/04/23 22:09:23 christos Exp $");
41*2639ae9bSBen Gras
42*2639ae9bSBen Gras /*
43*2639ae9bSBen Gras * PACKAGE: hash
44*2639ae9bSBen Gras *
45*2639ae9bSBen Gras * DESCRIPTION:
46*2639ae9bSBen Gras * Contains buffer management
47*2639ae9bSBen Gras *
48*2639ae9bSBen Gras * ROUTINES:
49*2639ae9bSBen Gras * External
50*2639ae9bSBen Gras * __buf_init
51*2639ae9bSBen Gras * __get_buf
52*2639ae9bSBen Gras * __buf_free
53*2639ae9bSBen Gras * __reclaim_buf
54*2639ae9bSBen Gras * Internal
55*2639ae9bSBen Gras * newbuf
56*2639ae9bSBen Gras */
57*2639ae9bSBen Gras
58*2639ae9bSBen Gras #include <sys/param.h>
59*2639ae9bSBen Gras
60*2639ae9bSBen Gras #include <errno.h>
61*2639ae9bSBen Gras #include <stddef.h>
62*2639ae9bSBen Gras #include <stdio.h>
63*2639ae9bSBen Gras #include <stdlib.h>
64*2639ae9bSBen Gras #include <string.h>
65*2639ae9bSBen Gras #include <assert.h>
66*2639ae9bSBen Gras
67*2639ae9bSBen Gras #include <db.h>
68*2639ae9bSBen Gras #include "hash.h"
69*2639ae9bSBen Gras #include "page.h"
70*2639ae9bSBen Gras #include "extern.h"
71*2639ae9bSBen Gras
72*2639ae9bSBen Gras static BUFHEAD *newbuf(HTAB *, uint32_t, BUFHEAD *);
73*2639ae9bSBen Gras
74*2639ae9bSBen Gras /* Unlink B from its place in the lru */
75*2639ae9bSBen Gras #define BUF_REMOVE(B) { \
76*2639ae9bSBen Gras (B)->prev->next = (B)->next; \
77*2639ae9bSBen Gras (B)->next->prev = (B)->prev; \
78*2639ae9bSBen Gras }
79*2639ae9bSBen Gras
80*2639ae9bSBen Gras /* Insert B after P */
81*2639ae9bSBen Gras #define BUF_INSERT(B, P) { \
82*2639ae9bSBen Gras (B)->next = (P)->next; \
83*2639ae9bSBen Gras (B)->prev = (P); \
84*2639ae9bSBen Gras (P)->next = (B); \
85*2639ae9bSBen Gras (B)->next->prev = (B); \
86*2639ae9bSBen Gras }
87*2639ae9bSBen Gras
88*2639ae9bSBen Gras #define MRU hashp->bufhead.next
89*2639ae9bSBen Gras #define LRU hashp->bufhead.prev
90*2639ae9bSBen Gras
91*2639ae9bSBen Gras #define MRU_INSERT(B) BUF_INSERT((B), &hashp->bufhead)
92*2639ae9bSBen Gras #define LRU_INSERT(B) BUF_INSERT((B), LRU)
93*2639ae9bSBen Gras
94*2639ae9bSBen Gras /*
95*2639ae9bSBen Gras * We are looking for a buffer with address "addr". If prev_bp is NULL, then
96*2639ae9bSBen Gras * address is a bucket index. If prev_bp is not NULL, then it points to the
97*2639ae9bSBen Gras * page previous to an overflow page that we are trying to find.
98*2639ae9bSBen Gras *
99*2639ae9bSBen Gras * CAVEAT: The buffer header accessed via prev_bp's ovfl field may no longer
100*2639ae9bSBen Gras * be valid. Therefore, you must always verify that its address matches the
101*2639ae9bSBen Gras * address you are seeking.
102*2639ae9bSBen Gras */
103*2639ae9bSBen Gras BUFHEAD *
__get_buf(HTAB * hashp,uint32_t addr,BUFHEAD * prev_bp,int newpage)104*2639ae9bSBen Gras __get_buf(
105*2639ae9bSBen Gras HTAB *hashp,
106*2639ae9bSBen Gras uint32_t addr,
107*2639ae9bSBen Gras BUFHEAD *prev_bp,
108*2639ae9bSBen Gras int newpage /* If prev_bp set, indicates a new overflow page. */
109*2639ae9bSBen Gras )
110*2639ae9bSBen Gras {
111*2639ae9bSBen Gras BUFHEAD *bp;
112*2639ae9bSBen Gras uint32_t is_disk_mask;
113*2639ae9bSBen Gras int is_disk, segment_ndx = 0; /* pacify gcc */
114*2639ae9bSBen Gras SEGMENT segp = NULL; /* pacify gcc */
115*2639ae9bSBen Gras
116*2639ae9bSBen Gras is_disk = 0;
117*2639ae9bSBen Gras is_disk_mask = 0;
118*2639ae9bSBen Gras if (prev_bp) {
119*2639ae9bSBen Gras bp = prev_bp->ovfl;
120*2639ae9bSBen Gras if (!bp || (bp->addr != addr))
121*2639ae9bSBen Gras bp = NULL;
122*2639ae9bSBen Gras if (!newpage)
123*2639ae9bSBen Gras is_disk = BUF_DISK;
124*2639ae9bSBen Gras } else {
125*2639ae9bSBen Gras /* Grab buffer out of directory */
126*2639ae9bSBen Gras segment_ndx = addr & (hashp->SGSIZE - 1);
127*2639ae9bSBen Gras
128*2639ae9bSBen Gras /* valid segment ensured by __call_hash() */
129*2639ae9bSBen Gras segp = hashp->dir[addr >> hashp->SSHIFT];
130*2639ae9bSBen Gras _DIAGASSERT(segp != NULL);
131*2639ae9bSBen Gras bp = PTROF(segp[segment_ndx]);
132*2639ae9bSBen Gras is_disk_mask = ISDISK(segp[segment_ndx]);
133*2639ae9bSBen Gras is_disk = is_disk_mask || !hashp->new_file;
134*2639ae9bSBen Gras }
135*2639ae9bSBen Gras
136*2639ae9bSBen Gras if (!bp) {
137*2639ae9bSBen Gras bp = newbuf(hashp, addr, prev_bp);
138*2639ae9bSBen Gras if (!bp ||
139*2639ae9bSBen Gras __get_page(hashp, bp->page, addr, !prev_bp, is_disk, 0))
140*2639ae9bSBen Gras return (NULL);
141*2639ae9bSBen Gras if (!prev_bp)
142*2639ae9bSBen Gras segp[segment_ndx] =
143*2639ae9bSBen Gras (BUFHEAD *)(void *)((u_long)bp | is_disk_mask);
144*2639ae9bSBen Gras } else {
145*2639ae9bSBen Gras BUF_REMOVE(bp);
146*2639ae9bSBen Gras MRU_INSERT(bp);
147*2639ae9bSBen Gras }
148*2639ae9bSBen Gras return (bp);
149*2639ae9bSBen Gras }
150*2639ae9bSBen Gras
151*2639ae9bSBen Gras /*
152*2639ae9bSBen Gras * We need a buffer for this page. Either allocate one, or evict a resident
153*2639ae9bSBen Gras * one (if we have as many buffers as we're allowed) and put this one in.
154*2639ae9bSBen Gras *
155*2639ae9bSBen Gras * If newbuf finds an error (returning NULL), it also sets errno.
156*2639ae9bSBen Gras */
157*2639ae9bSBen Gras static BUFHEAD *
newbuf(HTAB * hashp,uint32_t addr,BUFHEAD * prev_bp)158*2639ae9bSBen Gras newbuf(HTAB *hashp, uint32_t addr, BUFHEAD *prev_bp)
159*2639ae9bSBen Gras {
160*2639ae9bSBen Gras BUFHEAD *bp; /* The buffer we're going to use */
161*2639ae9bSBen Gras BUFHEAD *xbp; /* Temp pointer */
162*2639ae9bSBen Gras BUFHEAD *next_xbp;
163*2639ae9bSBen Gras SEGMENT segp;
164*2639ae9bSBen Gras int segment_ndx;
165*2639ae9bSBen Gras uint16_t oaddr, *shortp;
166*2639ae9bSBen Gras
167*2639ae9bSBen Gras oaddr = 0;
168*2639ae9bSBen Gras bp = LRU;
169*2639ae9bSBen Gras /*
170*2639ae9bSBen Gras * If LRU buffer is pinned, the buffer pool is too small. We need to
171*2639ae9bSBen Gras * allocate more buffers.
172*2639ae9bSBen Gras */
173*2639ae9bSBen Gras if (hashp->nbufs || (bp->flags & BUF_PIN)) {
174*2639ae9bSBen Gras /* Allocate a new one */
175*2639ae9bSBen Gras if ((bp = calloc(1, sizeof(BUFHEAD))) == NULL)
176*2639ae9bSBen Gras return (NULL);
177*2639ae9bSBen Gras if ((bp->page = calloc(1, (size_t)hashp->BSIZE)) == NULL) {
178*2639ae9bSBen Gras free(bp);
179*2639ae9bSBen Gras return (NULL);
180*2639ae9bSBen Gras }
181*2639ae9bSBen Gras if (hashp->nbufs)
182*2639ae9bSBen Gras hashp->nbufs--;
183*2639ae9bSBen Gras } else {
184*2639ae9bSBen Gras /* Kick someone out */
185*2639ae9bSBen Gras BUF_REMOVE(bp);
186*2639ae9bSBen Gras /*
187*2639ae9bSBen Gras * If this is an overflow page with addr 0, it's already been
188*2639ae9bSBen Gras * flushed back in an overflow chain and initialized.
189*2639ae9bSBen Gras */
190*2639ae9bSBen Gras if ((bp->addr != 0) || (bp->flags & BUF_BUCKET)) {
191*2639ae9bSBen Gras /*
192*2639ae9bSBen Gras * Set oaddr before __put_page so that you get it
193*2639ae9bSBen Gras * before bytes are swapped.
194*2639ae9bSBen Gras */
195*2639ae9bSBen Gras shortp = (uint16_t *)(void *)bp->page;
196*2639ae9bSBen Gras if (shortp[0])
197*2639ae9bSBen Gras oaddr = shortp[shortp[0] - 1];
198*2639ae9bSBen Gras if ((bp->flags & BUF_MOD) && __put_page(hashp, bp->page,
199*2639ae9bSBen Gras bp->addr, (int)IS_BUCKET(bp->flags), 0))
200*2639ae9bSBen Gras return (NULL);
201*2639ae9bSBen Gras /*
202*2639ae9bSBen Gras * Update the pointer to this page (i.e. invalidate it).
203*2639ae9bSBen Gras *
204*2639ae9bSBen Gras * If this is a new file (i.e. we created it at open
205*2639ae9bSBen Gras * time), make sure that we mark pages which have been
206*2639ae9bSBen Gras * written to disk so we retrieve them from disk later,
207*2639ae9bSBen Gras * rather than allocating new pages.
208*2639ae9bSBen Gras */
209*2639ae9bSBen Gras if (IS_BUCKET(bp->flags)) {
210*2639ae9bSBen Gras segment_ndx = bp->addr & (hashp->SGSIZE - 1);
211*2639ae9bSBen Gras segp = hashp->dir[bp->addr >> hashp->SSHIFT];
212*2639ae9bSBen Gras _DIAGASSERT(segp != NULL);
213*2639ae9bSBen Gras
214*2639ae9bSBen Gras if (hashp->new_file &&
215*2639ae9bSBen Gras ((bp->flags & BUF_MOD) ||
216*2639ae9bSBen Gras ISDISK(segp[segment_ndx])))
217*2639ae9bSBen Gras segp[segment_ndx] = (BUFHEAD *)BUF_DISK;
218*2639ae9bSBen Gras else
219*2639ae9bSBen Gras segp[segment_ndx] = NULL;
220*2639ae9bSBen Gras }
221*2639ae9bSBen Gras /*
222*2639ae9bSBen Gras * Since overflow pages can only be access by means of
223*2639ae9bSBen Gras * their bucket, free overflow pages associated with
224*2639ae9bSBen Gras * this bucket.
225*2639ae9bSBen Gras */
226*2639ae9bSBen Gras for (xbp = bp; xbp->ovfl;) {
227*2639ae9bSBen Gras next_xbp = xbp->ovfl;
228*2639ae9bSBen Gras xbp->ovfl = 0;
229*2639ae9bSBen Gras xbp = next_xbp;
230*2639ae9bSBen Gras
231*2639ae9bSBen Gras /* Check that ovfl pointer is up date. */
232*2639ae9bSBen Gras if (IS_BUCKET(xbp->flags) ||
233*2639ae9bSBen Gras (oaddr != xbp->addr))
234*2639ae9bSBen Gras break;
235*2639ae9bSBen Gras
236*2639ae9bSBen Gras shortp = (uint16_t *)(void *)xbp->page;
237*2639ae9bSBen Gras if (shortp[0])
238*2639ae9bSBen Gras /* set before __put_page */
239*2639ae9bSBen Gras oaddr = shortp[shortp[0] - 1];
240*2639ae9bSBen Gras if ((xbp->flags & BUF_MOD) && __put_page(hashp,
241*2639ae9bSBen Gras xbp->page, xbp->addr, 0, 0))
242*2639ae9bSBen Gras return (NULL);
243*2639ae9bSBen Gras xbp->addr = 0;
244*2639ae9bSBen Gras xbp->flags = 0;
245*2639ae9bSBen Gras BUF_REMOVE(xbp);
246*2639ae9bSBen Gras LRU_INSERT(xbp);
247*2639ae9bSBen Gras }
248*2639ae9bSBen Gras }
249*2639ae9bSBen Gras }
250*2639ae9bSBen Gras
251*2639ae9bSBen Gras /* Now assign this buffer */
252*2639ae9bSBen Gras bp->addr = addr;
253*2639ae9bSBen Gras #ifdef DEBUG1
254*2639ae9bSBen Gras (void)fprintf(stderr, "NEWBUF1: %d->ovfl was %d is now %d\n",
255*2639ae9bSBen Gras bp->addr, (bp->ovfl ? bp->ovfl->addr : 0), 0);
256*2639ae9bSBen Gras #endif
257*2639ae9bSBen Gras bp->ovfl = NULL;
258*2639ae9bSBen Gras if (prev_bp) {
259*2639ae9bSBen Gras /*
260*2639ae9bSBen Gras * If prev_bp is set, this is an overflow page, hook it in to
261*2639ae9bSBen Gras * the buffer overflow links.
262*2639ae9bSBen Gras */
263*2639ae9bSBen Gras #ifdef DEBUG1
264*2639ae9bSBen Gras (void)fprintf(stderr, "NEWBUF2: %d->ovfl was %d is now %d\n",
265*2639ae9bSBen Gras prev_bp->addr, (prev_bp->ovfl ? prev_bp->ovfl->addr : 0),
266*2639ae9bSBen Gras (bp ? bp->addr : 0));
267*2639ae9bSBen Gras #endif
268*2639ae9bSBen Gras prev_bp->ovfl = bp;
269*2639ae9bSBen Gras bp->flags = 0;
270*2639ae9bSBen Gras } else
271*2639ae9bSBen Gras bp->flags = BUF_BUCKET;
272*2639ae9bSBen Gras MRU_INSERT(bp);
273*2639ae9bSBen Gras return (bp);
274*2639ae9bSBen Gras }
275*2639ae9bSBen Gras
276*2639ae9bSBen Gras void
__buf_init(HTAB * hashp,u_int nbytes)277*2639ae9bSBen Gras __buf_init(HTAB *hashp, u_int nbytes)
278*2639ae9bSBen Gras {
279*2639ae9bSBen Gras BUFHEAD *bfp;
280*2639ae9bSBen Gras int npages;
281*2639ae9bSBen Gras
282*2639ae9bSBen Gras bfp = &(hashp->bufhead);
283*2639ae9bSBen Gras npages = (unsigned int)(nbytes + hashp->BSIZE - 1) >> hashp->BSHIFT;
284*2639ae9bSBen Gras npages = MAX(npages, MIN_BUFFERS);
285*2639ae9bSBen Gras
286*2639ae9bSBen Gras hashp->nbufs = npages;
287*2639ae9bSBen Gras bfp->next = bfp;
288*2639ae9bSBen Gras bfp->prev = bfp;
289*2639ae9bSBen Gras /*
290*2639ae9bSBen Gras * This space is calloc'd so these are already null.
291*2639ae9bSBen Gras *
292*2639ae9bSBen Gras * bfp->ovfl = NULL;
293*2639ae9bSBen Gras * bfp->flags = 0;
294*2639ae9bSBen Gras * bfp->page = NULL;
295*2639ae9bSBen Gras * bfp->addr = 0;
296*2639ae9bSBen Gras */
297*2639ae9bSBen Gras }
298*2639ae9bSBen Gras
299*2639ae9bSBen Gras int
__buf_free(HTAB * hashp,int do_free,int to_disk)300*2639ae9bSBen Gras __buf_free(HTAB *hashp, int do_free, int to_disk)
301*2639ae9bSBen Gras {
302*2639ae9bSBen Gras BUFHEAD *bp;
303*2639ae9bSBen Gras
304*2639ae9bSBen Gras /* Need to make sure that buffer manager has been initialized */
305*2639ae9bSBen Gras if (!LRU)
306*2639ae9bSBen Gras return (0);
307*2639ae9bSBen Gras for (bp = LRU; bp != &hashp->bufhead;) {
308*2639ae9bSBen Gras /* Check that the buffer is valid */
309*2639ae9bSBen Gras if (bp->addr || IS_BUCKET(bp->flags)) {
310*2639ae9bSBen Gras if (to_disk && (bp->flags & BUF_MOD) &&
311*2639ae9bSBen Gras __put_page(hashp, bp->page,
312*2639ae9bSBen Gras bp->addr, IS_BUCKET(bp->flags), 0))
313*2639ae9bSBen Gras return (-1);
314*2639ae9bSBen Gras }
315*2639ae9bSBen Gras /* Check if we are freeing stuff */
316*2639ae9bSBen Gras if (do_free) {
317*2639ae9bSBen Gras if (bp->page) {
318*2639ae9bSBen Gras (void)memset(bp->page, 0, (size_t)hashp->BSIZE);
319*2639ae9bSBen Gras free(bp->page);
320*2639ae9bSBen Gras }
321*2639ae9bSBen Gras BUF_REMOVE(bp);
322*2639ae9bSBen Gras free(bp);
323*2639ae9bSBen Gras bp = LRU;
324*2639ae9bSBen Gras } else
325*2639ae9bSBen Gras bp = bp->prev;
326*2639ae9bSBen Gras }
327*2639ae9bSBen Gras return (0);
328*2639ae9bSBen Gras }
329*2639ae9bSBen Gras
330*2639ae9bSBen Gras void
__reclaim_buf(HTAB * hashp,BUFHEAD * bp)331*2639ae9bSBen Gras __reclaim_buf(HTAB *hashp, BUFHEAD *bp)
332*2639ae9bSBen Gras {
333*2639ae9bSBen Gras bp->ovfl = 0;
334*2639ae9bSBen Gras bp->addr = 0;
335*2639ae9bSBen Gras bp->flags = 0;
336*2639ae9bSBen Gras BUF_REMOVE(bp);
337*2639ae9bSBen Gras LRU_INSERT(bp);
338*2639ae9bSBen Gras }
339