1*3240e6a8Sguenther /* $OpenBSD: hash.c,v 1.29 2016/09/21 04:38:56 guenther Exp $ */
21b727fc6Smillert
3df930be7Sderaadt /*-
4df930be7Sderaadt * Copyright (c) 1990, 1993, 1994
5df930be7Sderaadt * The Regents of the University of California. All rights reserved.
6df930be7Sderaadt *
7df930be7Sderaadt * This code is derived from software contributed to Berkeley by
8df930be7Sderaadt * Margo Seltzer.
9df930be7Sderaadt *
10df930be7Sderaadt * Redistribution and use in source and binary forms, with or without
11df930be7Sderaadt * modification, are permitted provided that the following conditions
12df930be7Sderaadt * are met:
13df930be7Sderaadt * 1. Redistributions of source code must retain the above copyright
14df930be7Sderaadt * notice, this list of conditions and the following disclaimer.
15df930be7Sderaadt * 2. Redistributions in binary form must reproduce the above copyright
16df930be7Sderaadt * notice, this list of conditions and the following disclaimer in the
17df930be7Sderaadt * documentation and/or other materials provided with the distribution.
186580fee3Smillert * 3. Neither the name of the University nor the names of its contributors
19df930be7Sderaadt * may be used to endorse or promote products derived from this software
20df930be7Sderaadt * without specific prior written permission.
21df930be7Sderaadt *
22df930be7Sderaadt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23df930be7Sderaadt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24df930be7Sderaadt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25df930be7Sderaadt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26df930be7Sderaadt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27df930be7Sderaadt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28df930be7Sderaadt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29df930be7Sderaadt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30df930be7Sderaadt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31df930be7Sderaadt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32df930be7Sderaadt * SUCH DAMAGE.
33df930be7Sderaadt */
34df930be7Sderaadt
35df930be7Sderaadt #include <sys/stat.h>
36df930be7Sderaadt
37df930be7Sderaadt #include <errno.h>
38df930be7Sderaadt #include <fcntl.h>
39df930be7Sderaadt #include <stdio.h>
40df930be7Sderaadt #include <stdlib.h>
41df930be7Sderaadt #include <string.h>
42df930be7Sderaadt #include <unistd.h>
43df930be7Sderaadt #ifdef DEBUG
44df930be7Sderaadt #include <assert.h>
45df930be7Sderaadt #endif
46df930be7Sderaadt
47df930be7Sderaadt #include <db.h>
48df930be7Sderaadt #include "hash.h"
49df930be7Sderaadt #include "page.h"
50df930be7Sderaadt #include "extern.h"
51df930be7Sderaadt
52aea60beeSderaadt #define MAXIMUM(a, b) (((a) > (b)) ? (a) : (b))
53aea60beeSderaadt
54c72b5b24Smillert static int alloc_segs(HTAB *, int);
55c72b5b24Smillert static int flush_meta(HTAB *);
56c72b5b24Smillert static int hash_access(HTAB *, ACTION, DBT *, DBT *);
57c72b5b24Smillert static int hash_close(DB *);
58c72b5b24Smillert static int hash_delete(const DB *, const DBT *, u_int32_t);
59c72b5b24Smillert static int hash_fd(const DB *);
60c72b5b24Smillert static int hash_get(const DB *, const DBT *, DBT *, u_int32_t);
61c72b5b24Smillert static int hash_put(const DB *, DBT *, const DBT *, u_int32_t);
62c72b5b24Smillert static void *hash_realloc(SEGMENT **, int, int);
63c72b5b24Smillert static int hash_seq(const DB *, DBT *, DBT *, u_int32_t);
64c72b5b24Smillert static int hash_sync(const DB *, u_int32_t);
65c72b5b24Smillert static int hdestroy(HTAB *);
66f5f3a36bSguenther static HTAB *init_hash(HTAB *, const char *, const HASHINFO *);
67c72b5b24Smillert static int init_htab(HTAB *, int);
68df930be7Sderaadt #if BYTE_ORDER == LITTLE_ENDIAN
69c72b5b24Smillert static void swap_header(HTAB *);
70c72b5b24Smillert static void swap_header_copy(HASHHDR *, HASHHDR *);
71df930be7Sderaadt #endif
72df930be7Sderaadt
73df930be7Sderaadt /* Fast arithmetic, relying on powers of 2, */
74df930be7Sderaadt #define MOD(x, y) ((x) & ((y) - 1))
75df930be7Sderaadt
76df930be7Sderaadt #define RETURN_ERROR(ERR, LOC) { save_errno = ERR; goto LOC; }
77df930be7Sderaadt
78df930be7Sderaadt /* Return values */
79df930be7Sderaadt #define SUCCESS (0)
80df930be7Sderaadt #define ERROR (-1)
81df930be7Sderaadt #define ABNORMAL (1)
82df930be7Sderaadt
83df930be7Sderaadt #ifdef HASH_STATISTICS
84df930be7Sderaadt int hash_accesses, hash_collisions, hash_expansions, hash_overflows;
85df930be7Sderaadt #endif
86df930be7Sderaadt
87df930be7Sderaadt /************************** INTERFACE ROUTINES ***************************/
88df930be7Sderaadt /* OPEN/CLOSE */
89df930be7Sderaadt
90e20a56a5Sotto DB *
__hash_open(const char * file,int flags,int mode,const HASHINFO * info,int dflags)91e20a56a5Sotto __hash_open(const char *file, int flags, int mode,
92e20a56a5Sotto const HASHINFO *info, /* Special directives for create */
93e20a56a5Sotto int dflags)
94df930be7Sderaadt {
95df930be7Sderaadt HTAB *hashp;
96df930be7Sderaadt struct stat statbuf;
97df930be7Sderaadt DB *dbp;
989a1282d0Smillert int bpages, hdrsize, new_table, nsegs, save_errno;
99df930be7Sderaadt
100df930be7Sderaadt if ((flags & O_ACCMODE) == O_WRONLY) {
101df930be7Sderaadt errno = EINVAL;
102df930be7Sderaadt return (NULL);
103df930be7Sderaadt }
104df95a199Smillert
105df930be7Sderaadt if (!(hashp = (HTAB *)calloc(1, sizeof(HTAB))))
106df930be7Sderaadt return (NULL);
107df930be7Sderaadt hashp->fp = -1;
108df930be7Sderaadt
109df930be7Sderaadt /*
110df930be7Sderaadt * Even if user wants write only, we need to be able to read
111df930be7Sderaadt * the actual file, so we need to open it read/write. But, the
112df930be7Sderaadt * field in the hashp structure needs to be accurate so that
113df930be7Sderaadt * we can check accesses.
114df930be7Sderaadt */
115df930be7Sderaadt hashp->flags = flags;
116df930be7Sderaadt
117df930be7Sderaadt if (file) {
1180205f8e6Sguenther if ((hashp->fp = open(file, flags | O_CLOEXEC, mode)) == -1)
119df930be7Sderaadt RETURN_ERROR(errno, error0);
1209a1282d0Smillert new_table = fstat(hashp->fp, &statbuf) == 0 &&
1219a1282d0Smillert statbuf.st_size == 0 && (flags & O_ACCMODE) != O_RDONLY;
1229a1282d0Smillert } else
1239a1282d0Smillert new_table = 1;
1249a1282d0Smillert
125df930be7Sderaadt if (new_table) {
126f5f3a36bSguenther if (!(hashp = init_hash(hashp, file, info)))
127df930be7Sderaadt RETURN_ERROR(errno, error1);
128df930be7Sderaadt } else {
129df930be7Sderaadt /* Table already exists */
130df930be7Sderaadt if (info && info->hash)
131df930be7Sderaadt hashp->hash = info->hash;
132df930be7Sderaadt else
133df930be7Sderaadt hashp->hash = __default_hash;
134df930be7Sderaadt
135df930be7Sderaadt hdrsize = read(hashp->fp, &hashp->hdr, sizeof(HASHHDR));
136df930be7Sderaadt #if BYTE_ORDER == LITTLE_ENDIAN
137df930be7Sderaadt swap_header(hashp);
138df930be7Sderaadt #endif
139df930be7Sderaadt if (hdrsize == -1)
140df930be7Sderaadt RETURN_ERROR(errno, error1);
141df930be7Sderaadt if (hdrsize != sizeof(HASHHDR))
142df930be7Sderaadt RETURN_ERROR(EFTYPE, error1);
143df930be7Sderaadt /* Verify file type, versions and hash function */
144df930be7Sderaadt if (hashp->MAGIC != HASHMAGIC)
145df930be7Sderaadt RETURN_ERROR(EFTYPE, error1);
146df930be7Sderaadt #define OLDHASHVERSION 1
147df930be7Sderaadt if (hashp->VERSION != HASHVERSION &&
148df930be7Sderaadt hashp->VERSION != OLDHASHVERSION)
149df930be7Sderaadt RETURN_ERROR(EFTYPE, error1);
150df930be7Sderaadt if (hashp->hash(CHARKEY, sizeof(CHARKEY)) != hashp->H_CHARKEY)
151df930be7Sderaadt RETURN_ERROR(EFTYPE, error1);
152df930be7Sderaadt /*
153df930be7Sderaadt * Figure out how many segments we need. Max_Bucket is the
154df930be7Sderaadt * maximum bucket number, so the number of buckets is
155df930be7Sderaadt * max_bucket + 1.
156df930be7Sderaadt */
157df930be7Sderaadt nsegs = (hashp->MAX_BUCKET + 1 + hashp->SGSIZE - 1) /
158df930be7Sderaadt hashp->SGSIZE;
159df930be7Sderaadt if (alloc_segs(hashp, nsegs))
160df930be7Sderaadt /*
161df930be7Sderaadt * If alloc_segs fails, table will have been destroyed
162df930be7Sderaadt * and errno will have been set.
163df930be7Sderaadt */
164df930be7Sderaadt return (NULL);
165df930be7Sderaadt /* Read in bitmaps */
166df930be7Sderaadt bpages = (hashp->SPARES[hashp->OVFL_POINT] +
167df930be7Sderaadt (hashp->BSIZE << BYTE_SHIFT) - 1) >>
168df930be7Sderaadt (hashp->BSHIFT + BYTE_SHIFT);
169df930be7Sderaadt
170df930be7Sderaadt hashp->nmaps = bpages;
171df930be7Sderaadt (void)memset(&hashp->mapp[0], 0, bpages * sizeof(u_int32_t *));
172df930be7Sderaadt }
173df930be7Sderaadt
174df930be7Sderaadt /* Initialize Buffer Manager */
175df930be7Sderaadt if (info && info->cachesize)
176df930be7Sderaadt __buf_init(hashp, info->cachesize);
177df930be7Sderaadt else
178df930be7Sderaadt __buf_init(hashp, DEF_BUFSIZE);
179df930be7Sderaadt
180df930be7Sderaadt hashp->new_file = new_table;
181df930be7Sderaadt hashp->save_file = file && (hashp->flags & O_RDWR);
182df930be7Sderaadt hashp->cbucket = -1;
183df930be7Sderaadt if (!(dbp = (DB *)malloc(sizeof(DB)))) {
184df930be7Sderaadt save_errno = errno;
185df930be7Sderaadt hdestroy(hashp);
186df930be7Sderaadt errno = save_errno;
187df930be7Sderaadt return (NULL);
188df930be7Sderaadt }
189df930be7Sderaadt dbp->internal = hashp;
190df930be7Sderaadt dbp->close = hash_close;
191df930be7Sderaadt dbp->del = hash_delete;
192df930be7Sderaadt dbp->fd = hash_fd;
193df930be7Sderaadt dbp->get = hash_get;
194df930be7Sderaadt dbp->put = hash_put;
195df930be7Sderaadt dbp->seq = hash_seq;
196df930be7Sderaadt dbp->sync = hash_sync;
197df930be7Sderaadt dbp->type = DB_HASH;
198df930be7Sderaadt
199df930be7Sderaadt #ifdef DEBUG
200df930be7Sderaadt (void)fprintf(stderr,
201df95a199Smillert "%s\n%s%p\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%x\n%s%x\n%s%d\n%s%d\n",
202df930be7Sderaadt "init_htab:",
203df930be7Sderaadt "TABLE POINTER ", hashp,
204df930be7Sderaadt "BUCKET SIZE ", hashp->BSIZE,
205df930be7Sderaadt "BUCKET SHIFT ", hashp->BSHIFT,
206df930be7Sderaadt "DIRECTORY SIZE ", hashp->DSIZE,
207df930be7Sderaadt "SEGMENT SIZE ", hashp->SGSIZE,
208df930be7Sderaadt "SEGMENT SHIFT ", hashp->SSHIFT,
209df930be7Sderaadt "FILL FACTOR ", hashp->FFACTOR,
210df930be7Sderaadt "MAX BUCKET ", hashp->MAX_BUCKET,
211df930be7Sderaadt "OVFL POINT ", hashp->OVFL_POINT,
212df930be7Sderaadt "LAST FREED ", hashp->LAST_FREED,
213df930be7Sderaadt "HIGH MASK ", hashp->HIGH_MASK,
214df930be7Sderaadt "LOW MASK ", hashp->LOW_MASK,
215df930be7Sderaadt "NSEGS ", hashp->nsegs,
216df930be7Sderaadt "NKEYS ", hashp->NKEYS);
217df930be7Sderaadt #endif
218df930be7Sderaadt #ifdef HASH_STATISTICS
219df930be7Sderaadt hash_overflows = hash_accesses = hash_collisions = hash_expansions = 0;
220df930be7Sderaadt #endif
221df930be7Sderaadt return (dbp);
222df930be7Sderaadt
223df930be7Sderaadt error1:
224df930be7Sderaadt if (hashp != NULL)
225df930be7Sderaadt (void)close(hashp->fp);
226df930be7Sderaadt
227df930be7Sderaadt error0:
228df930be7Sderaadt free(hashp);
229df930be7Sderaadt errno = save_errno;
230df930be7Sderaadt return (NULL);
231df930be7Sderaadt }
232df930be7Sderaadt
233df930be7Sderaadt static int
hash_close(DB * dbp)234e20a56a5Sotto hash_close(DB *dbp)
235df930be7Sderaadt {
236df930be7Sderaadt HTAB *hashp;
237df930be7Sderaadt int retval;
238df930be7Sderaadt
239df930be7Sderaadt if (!dbp)
240df930be7Sderaadt return (ERROR);
241df930be7Sderaadt
242df930be7Sderaadt hashp = (HTAB *)dbp->internal;
243df930be7Sderaadt retval = hdestroy(hashp);
244df930be7Sderaadt free(dbp);
245df930be7Sderaadt return (retval);
246df930be7Sderaadt }
247df930be7Sderaadt
248df930be7Sderaadt static int
hash_fd(const DB * dbp)249e20a56a5Sotto hash_fd(const DB *dbp)
250df930be7Sderaadt {
251df930be7Sderaadt HTAB *hashp;
252df930be7Sderaadt
253df930be7Sderaadt if (!dbp)
254df930be7Sderaadt return (ERROR);
255df930be7Sderaadt
256df930be7Sderaadt hashp = (HTAB *)dbp->internal;
257df930be7Sderaadt if (hashp->fp == -1) {
258df930be7Sderaadt errno = ENOENT;
259df930be7Sderaadt return (-1);
260df930be7Sderaadt }
261df930be7Sderaadt return (hashp->fp);
262df930be7Sderaadt }
263df930be7Sderaadt
264df930be7Sderaadt /************************** LOCAL CREATION ROUTINES **********************/
265df930be7Sderaadt static HTAB *
init_hash(HTAB * hashp,const char * file,const HASHINFO * info)266f5f3a36bSguenther init_hash(HTAB *hashp, const char *file, const HASHINFO *info)
267df930be7Sderaadt {
268df930be7Sderaadt struct stat statbuf;
269df930be7Sderaadt int nelem;
270df930be7Sderaadt
271df930be7Sderaadt nelem = 1;
272df930be7Sderaadt hashp->NKEYS = 0;
273df930be7Sderaadt hashp->LORDER = BYTE_ORDER;
274df930be7Sderaadt hashp->BSIZE = DEF_BUCKET_SIZE;
275df930be7Sderaadt hashp->BSHIFT = DEF_BUCKET_SHIFT;
276df930be7Sderaadt hashp->SGSIZE = DEF_SEGSIZE;
277df930be7Sderaadt hashp->SSHIFT = DEF_SEGSIZE_SHIFT;
278df930be7Sderaadt hashp->DSIZE = DEF_DIRSIZE;
279df930be7Sderaadt hashp->FFACTOR = DEF_FFACTOR;
280df930be7Sderaadt hashp->hash = __default_hash;
281df930be7Sderaadt memset(hashp->SPARES, 0, sizeof(hashp->SPARES));
282df930be7Sderaadt memset(hashp->BITMAPS, 0, sizeof (hashp->BITMAPS));
283df930be7Sderaadt
284df930be7Sderaadt /* Fix bucket size to be optimal for file system */
285df930be7Sderaadt if (file != NULL) {
286df930be7Sderaadt if (stat(file, &statbuf))
287df930be7Sderaadt return (NULL);
288df930be7Sderaadt hashp->BSIZE = statbuf.st_blksize;
289df930be7Sderaadt hashp->BSHIFT = __log2(hashp->BSIZE);
290df930be7Sderaadt }
291df930be7Sderaadt
292df930be7Sderaadt if (info) {
293df930be7Sderaadt if (info->bsize) {
294df930be7Sderaadt /* Round pagesize up to power of 2 */
295df930be7Sderaadt hashp->BSHIFT = __log2(info->bsize);
296df930be7Sderaadt hashp->BSIZE = 1 << hashp->BSHIFT;
297df930be7Sderaadt if (hashp->BSIZE > MAX_BSIZE) {
298df930be7Sderaadt errno = EINVAL;
299df930be7Sderaadt return (NULL);
300df930be7Sderaadt }
301df930be7Sderaadt }
302df930be7Sderaadt if (info->ffactor)
303df930be7Sderaadt hashp->FFACTOR = info->ffactor;
304df930be7Sderaadt if (info->hash)
305df930be7Sderaadt hashp->hash = info->hash;
306df930be7Sderaadt if (info->nelem)
307df930be7Sderaadt nelem = info->nelem;
308df930be7Sderaadt if (info->lorder) {
309df930be7Sderaadt if (info->lorder != BIG_ENDIAN &&
310df930be7Sderaadt info->lorder != LITTLE_ENDIAN) {
311df930be7Sderaadt errno = EINVAL;
312df930be7Sderaadt return (NULL);
313df930be7Sderaadt }
314df930be7Sderaadt hashp->LORDER = info->lorder;
315df930be7Sderaadt }
316df930be7Sderaadt }
317df930be7Sderaadt /* init_htab should destroy the table and set errno if it fails */
318df930be7Sderaadt if (init_htab(hashp, nelem))
319df930be7Sderaadt return (NULL);
320df930be7Sderaadt else
321df930be7Sderaadt return (hashp);
322df930be7Sderaadt }
323df930be7Sderaadt /*
324df930be7Sderaadt * This calls alloc_segs which may run out of memory. Alloc_segs will destroy
325df930be7Sderaadt * the table and set errno, so we just pass the error information along.
326df930be7Sderaadt *
327df930be7Sderaadt * Returns 0 on No Error
328df930be7Sderaadt */
329df930be7Sderaadt static int
init_htab(HTAB * hashp,int nelem)330e20a56a5Sotto init_htab(HTAB *hashp, int nelem)
331df930be7Sderaadt {
3326c51c909Smillert int nbuckets, nsegs, l2;
333df930be7Sderaadt
334df930be7Sderaadt /*
335df930be7Sderaadt * Divide number of elements by the fill factor and determine a
336df930be7Sderaadt * desired number of buckets. Allocate space for the next greater
337df930be7Sderaadt * power of two number of buckets.
338df930be7Sderaadt */
339df930be7Sderaadt nelem = (nelem - 1) / hashp->FFACTOR + 1;
340df930be7Sderaadt
341aea60beeSderaadt l2 = __log2(MAXIMUM(nelem, 2));
342df930be7Sderaadt nbuckets = 1 << l2;
343df930be7Sderaadt
344df930be7Sderaadt hashp->SPARES[l2] = l2 + 1;
345df930be7Sderaadt hashp->SPARES[l2 + 1] = l2 + 1;
346df930be7Sderaadt hashp->OVFL_POINT = l2;
347df930be7Sderaadt hashp->LAST_FREED = 2;
348df930be7Sderaadt
349df930be7Sderaadt /* First bitmap page is at: splitpoint l2 page offset 1 */
350df930be7Sderaadt if (__ibitmap(hashp, OADDR_OF(l2, 1), l2 + 1, 0))
351df930be7Sderaadt return (-1);
352df930be7Sderaadt
353df930be7Sderaadt hashp->MAX_BUCKET = hashp->LOW_MASK = nbuckets - 1;
354df930be7Sderaadt hashp->HIGH_MASK = (nbuckets << 1) - 1;
355aea60beeSderaadt hashp->HDRPAGES = ((MAXIMUM(sizeof(HASHHDR), MINHDRSIZE) - 1) >>
356df930be7Sderaadt hashp->BSHIFT) + 1;
357df930be7Sderaadt
358df930be7Sderaadt nsegs = (nbuckets - 1) / hashp->SGSIZE + 1;
359df930be7Sderaadt nsegs = 1 << __log2(nsegs);
360df930be7Sderaadt
361df930be7Sderaadt if (nsegs > hashp->DSIZE)
362df930be7Sderaadt hashp->DSIZE = nsegs;
363df930be7Sderaadt return (alloc_segs(hashp, nsegs));
364df930be7Sderaadt }
365df930be7Sderaadt
366df930be7Sderaadt /********************** DESTROY/CLOSE ROUTINES ************************/
367df930be7Sderaadt
368df930be7Sderaadt /*
369df930be7Sderaadt * Flushes any changes to the file if necessary and destroys the hashp
370df930be7Sderaadt * structure, freeing all allocated space.
371df930be7Sderaadt */
372df930be7Sderaadt static int
hdestroy(HTAB * hashp)373e20a56a5Sotto hdestroy(HTAB *hashp)
374df930be7Sderaadt {
375df930be7Sderaadt int i, save_errno;
376df930be7Sderaadt
377df930be7Sderaadt save_errno = 0;
378df930be7Sderaadt
379df930be7Sderaadt #ifdef HASH_STATISTICS
380df930be7Sderaadt (void)fprintf(stderr, "hdestroy: accesses %ld collisions %ld\n",
381df930be7Sderaadt hash_accesses, hash_collisions);
382df930be7Sderaadt (void)fprintf(stderr, "hdestroy: expansions %ld\n",
383df930be7Sderaadt hash_expansions);
384df930be7Sderaadt (void)fprintf(stderr, "hdestroy: overflows %ld\n",
385df930be7Sderaadt hash_overflows);
386df930be7Sderaadt (void)fprintf(stderr, "keys %ld maxp %d segmentcount %d\n",
387df930be7Sderaadt hashp->NKEYS, hashp->MAX_BUCKET, hashp->nsegs);
388df930be7Sderaadt
389df930be7Sderaadt for (i = 0; i < NCACHED; i++)
390df930be7Sderaadt (void)fprintf(stderr,
391df930be7Sderaadt "spares[%d] = %d\n", i, hashp->SPARES[i]);
392df930be7Sderaadt #endif
393df930be7Sderaadt /*
394df930be7Sderaadt * Call on buffer manager to free buffers, and if required,
395df930be7Sderaadt * write them to disk.
396df930be7Sderaadt */
397df930be7Sderaadt if (__buf_free(hashp, 1, hashp->save_file))
398df930be7Sderaadt save_errno = errno;
399df930be7Sderaadt if (hashp->dir) {
400df930be7Sderaadt free(*hashp->dir); /* Free initial segments */
401df930be7Sderaadt /* Free extra segments */
402df930be7Sderaadt while (hashp->exsegs--)
403df930be7Sderaadt free(hashp->dir[--hashp->nsegs]);
404df930be7Sderaadt free(hashp->dir);
405df930be7Sderaadt }
406df930be7Sderaadt if (flush_meta(hashp) && !save_errno)
407df930be7Sderaadt save_errno = errno;
408df930be7Sderaadt /* Free Bigmaps */
409df930be7Sderaadt for (i = 0; i < hashp->nmaps; i++)
410df930be7Sderaadt free(hashp->mapp[i]);
41158071879Smillert free(hashp->tmp_key);
41258071879Smillert free(hashp->tmp_buf);
413df930be7Sderaadt
414df930be7Sderaadt if (hashp->fp != -1)
415df930be7Sderaadt (void)close(hashp->fp);
416df930be7Sderaadt
417df930be7Sderaadt free(hashp);
418df930be7Sderaadt
419df930be7Sderaadt if (save_errno) {
420df930be7Sderaadt errno = save_errno;
421df930be7Sderaadt return (ERROR);
422df930be7Sderaadt }
423df930be7Sderaadt return (SUCCESS);
424df930be7Sderaadt }
425df930be7Sderaadt /*
426df930be7Sderaadt * Write modified pages to disk
427df930be7Sderaadt *
428df930be7Sderaadt * Returns:
429df930be7Sderaadt * 0 == OK
430df930be7Sderaadt * -1 ERROR
431df930be7Sderaadt */
432df930be7Sderaadt static int
hash_sync(const DB * dbp,u_int32_t flags)433e20a56a5Sotto hash_sync(const DB *dbp, u_int32_t flags)
434df930be7Sderaadt {
435df930be7Sderaadt HTAB *hashp;
436df930be7Sderaadt
437df930be7Sderaadt if (flags != 0) {
438df930be7Sderaadt errno = EINVAL;
439df930be7Sderaadt return (ERROR);
440df930be7Sderaadt }
441df930be7Sderaadt
442df930be7Sderaadt if (!dbp)
443df930be7Sderaadt return (ERROR);
444df930be7Sderaadt
445df930be7Sderaadt hashp = (HTAB *)dbp->internal;
446df930be7Sderaadt if (!hashp->save_file)
447df930be7Sderaadt return (0);
448df930be7Sderaadt if (__buf_free(hashp, 0, 1) || flush_meta(hashp))
449df930be7Sderaadt return (ERROR);
450df930be7Sderaadt hashp->new_file = 0;
451df930be7Sderaadt return (0);
452df930be7Sderaadt }
453df930be7Sderaadt
454df930be7Sderaadt /*
455df930be7Sderaadt * Returns:
456df930be7Sderaadt * 0 == OK
457df930be7Sderaadt * -1 indicates that errno should be set
458df930be7Sderaadt */
459df930be7Sderaadt static int
flush_meta(HTAB * hashp)460e20a56a5Sotto flush_meta(HTAB *hashp)
461df930be7Sderaadt {
462df930be7Sderaadt HASHHDR *whdrp;
463df930be7Sderaadt #if BYTE_ORDER == LITTLE_ENDIAN
464df930be7Sderaadt HASHHDR whdr;
465df930be7Sderaadt #endif
466df930be7Sderaadt int fp, i, wsize;
467df930be7Sderaadt
468df930be7Sderaadt if (!hashp->save_file)
469df930be7Sderaadt return (0);
470df930be7Sderaadt hashp->MAGIC = HASHMAGIC;
471df930be7Sderaadt hashp->VERSION = HASHVERSION;
472df930be7Sderaadt hashp->H_CHARKEY = hashp->hash(CHARKEY, sizeof(CHARKEY));
473df930be7Sderaadt
474df930be7Sderaadt fp = hashp->fp;
475df930be7Sderaadt whdrp = &hashp->hdr;
476df930be7Sderaadt #if BYTE_ORDER == LITTLE_ENDIAN
477df930be7Sderaadt whdrp = &whdr;
478df930be7Sderaadt swap_header_copy(&hashp->hdr, whdrp);
479df930be7Sderaadt #endif
480*3240e6a8Sguenther if ((wsize = pwrite(fp, whdrp, sizeof(HASHHDR), 0)) == -1)
481df930be7Sderaadt return (-1);
482df930be7Sderaadt else
483df930be7Sderaadt if (wsize != sizeof(HASHHDR)) {
484df930be7Sderaadt errno = EFTYPE;
485c7cc963cSmarc hashp->err = errno;
486df930be7Sderaadt return (-1);
487df930be7Sderaadt }
488df930be7Sderaadt for (i = 0; i < NCACHED; i++)
489df930be7Sderaadt if (hashp->mapp[i])
490df930be7Sderaadt if (__put_page(hashp, (char *)hashp->mapp[i],
491df930be7Sderaadt hashp->BITMAPS[i], 0, 1))
492df930be7Sderaadt return (-1);
493df930be7Sderaadt return (0);
494df930be7Sderaadt }
495df930be7Sderaadt
496df930be7Sderaadt /*******************************SEARCH ROUTINES *****************************/
497df930be7Sderaadt /*
498df930be7Sderaadt * All the access routines return
499df930be7Sderaadt *
500df930be7Sderaadt * Returns:
501df930be7Sderaadt * 0 on SUCCESS
502df930be7Sderaadt * 1 to indicate an external ERROR (i.e. key not found, etc)
503df930be7Sderaadt * -1 to indicate an internal ERROR (i.e. out of memory, etc)
504df930be7Sderaadt */
505df930be7Sderaadt static int
hash_get(const DB * dbp,const DBT * key,DBT * data,u_int32_t flag)506e20a56a5Sotto hash_get(const DB *dbp, const DBT *key, DBT *data, u_int32_t flag)
507df930be7Sderaadt {
508df930be7Sderaadt HTAB *hashp;
509df930be7Sderaadt
510df930be7Sderaadt hashp = (HTAB *)dbp->internal;
511df930be7Sderaadt if (flag) {
512c7cc963cSmarc hashp->err = errno = EINVAL;
513df930be7Sderaadt return (ERROR);
514df930be7Sderaadt }
515df930be7Sderaadt return (hash_access(hashp, HASH_GET, (DBT *)key, data));
516df930be7Sderaadt }
517df930be7Sderaadt
518df930be7Sderaadt static int
hash_put(const DB * dbp,DBT * key,const DBT * data,u_int32_t flag)519e20a56a5Sotto hash_put(const DB *dbp, DBT *key, const DBT *data, u_int32_t flag)
520df930be7Sderaadt {
521df930be7Sderaadt HTAB *hashp;
522df930be7Sderaadt
523df930be7Sderaadt hashp = (HTAB *)dbp->internal;
524df930be7Sderaadt if (flag && flag != R_NOOVERWRITE) {
525c7cc963cSmarc hashp->err = errno = EINVAL;
526df930be7Sderaadt return (ERROR);
527df930be7Sderaadt }
528df930be7Sderaadt if ((hashp->flags & O_ACCMODE) == O_RDONLY) {
529c7cc963cSmarc hashp->err = errno = EPERM;
530df930be7Sderaadt return (ERROR);
531df930be7Sderaadt }
532df930be7Sderaadt return (hash_access(hashp, flag == R_NOOVERWRITE ?
533df930be7Sderaadt HASH_PUTNEW : HASH_PUT, (DBT *)key, (DBT *)data));
534df930be7Sderaadt }
535df930be7Sderaadt
536df930be7Sderaadt static int
hash_delete(const DB * dbp,const DBT * key,u_int32_t flag)537e20a56a5Sotto hash_delete(const DB *dbp, const DBT *key,
538e20a56a5Sotto u_int32_t flag) /* Ignored */
539df930be7Sderaadt {
540df930be7Sderaadt HTAB *hashp;
541df930be7Sderaadt
542df930be7Sderaadt hashp = (HTAB *)dbp->internal;
543df930be7Sderaadt if (flag && flag != R_CURSOR) {
544c7cc963cSmarc hashp->err = errno = EINVAL;
545df930be7Sderaadt return (ERROR);
546df930be7Sderaadt }
547df930be7Sderaadt if ((hashp->flags & O_ACCMODE) == O_RDONLY) {
548c7cc963cSmarc hashp->err = errno = EPERM;
549df930be7Sderaadt return (ERROR);
550df930be7Sderaadt }
551df930be7Sderaadt return (hash_access(hashp, HASH_DELETE, (DBT *)key, NULL));
552df930be7Sderaadt }
553df930be7Sderaadt
554df930be7Sderaadt /*
555df930be7Sderaadt * Assume that hashp has been set in wrapper routine.
556df930be7Sderaadt */
557df930be7Sderaadt static int
hash_access(HTAB * hashp,ACTION action,DBT * key,DBT * val)558e20a56a5Sotto hash_access(HTAB *hashp, ACTION action, DBT *key, DBT *val)
559df930be7Sderaadt {
5606c51c909Smillert BUFHEAD *rbufp;
561df930be7Sderaadt BUFHEAD *bufp, *save_bufp;
5626c51c909Smillert u_int16_t *bp;
5636c51c909Smillert int n, ndx, off, size;
5646c51c909Smillert char *kp;
565df930be7Sderaadt u_int16_t pageno;
566df930be7Sderaadt
567df930be7Sderaadt #ifdef HASH_STATISTICS
568df930be7Sderaadt hash_accesses++;
569df930be7Sderaadt #endif
570df930be7Sderaadt
571df930be7Sderaadt off = hashp->BSIZE;
572df930be7Sderaadt size = key->size;
573df930be7Sderaadt kp = (char *)key->data;
574df930be7Sderaadt rbufp = __get_buf(hashp, __call_hash(hashp, kp, size), NULL, 0);
575df930be7Sderaadt if (!rbufp)
576df930be7Sderaadt return (ERROR);
577df930be7Sderaadt save_bufp = rbufp;
578df930be7Sderaadt
579df930be7Sderaadt /* Pin the bucket chain */
580df930be7Sderaadt rbufp->flags |= BUF_PIN;
581df930be7Sderaadt for (bp = (u_int16_t *)rbufp->page, n = *bp++, ndx = 1; ndx < n;)
582df930be7Sderaadt if (bp[1] >= REAL_KEY) {
583df930be7Sderaadt /* Real key/data pair */
584df930be7Sderaadt if (size == off - *bp &&
585df930be7Sderaadt memcmp(kp, rbufp->page + *bp, size) == 0)
586df930be7Sderaadt goto found;
587df930be7Sderaadt off = bp[1];
588df930be7Sderaadt #ifdef HASH_STATISTICS
589df930be7Sderaadt hash_collisions++;
590df930be7Sderaadt #endif
591df930be7Sderaadt bp += 2;
592df930be7Sderaadt ndx += 2;
593df930be7Sderaadt } else if (bp[1] == OVFLPAGE) {
594df930be7Sderaadt rbufp = __get_buf(hashp, *bp, rbufp, 0);
595df930be7Sderaadt if (!rbufp) {
596df930be7Sderaadt save_bufp->flags &= ~BUF_PIN;
597df930be7Sderaadt return (ERROR);
598df930be7Sderaadt }
599df930be7Sderaadt /* FOR LOOP INIT */
600df930be7Sderaadt bp = (u_int16_t *)rbufp->page;
601df930be7Sderaadt n = *bp++;
602df930be7Sderaadt ndx = 1;
603df930be7Sderaadt off = hashp->BSIZE;
604df930be7Sderaadt } else if (bp[1] < REAL_KEY) {
605df930be7Sderaadt if ((ndx =
606df930be7Sderaadt __find_bigpair(hashp, rbufp, ndx, kp, size)) > 0)
607df930be7Sderaadt goto found;
608df930be7Sderaadt if (ndx == -2) {
609df930be7Sderaadt bufp = rbufp;
610df930be7Sderaadt if (!(pageno =
611df930be7Sderaadt __find_last_page(hashp, &bufp))) {
612df930be7Sderaadt ndx = 0;
613df930be7Sderaadt rbufp = bufp;
614df930be7Sderaadt break; /* FOR */
615df930be7Sderaadt }
616df930be7Sderaadt rbufp = __get_buf(hashp, pageno, bufp, 0);
617df930be7Sderaadt if (!rbufp) {
618df930be7Sderaadt save_bufp->flags &= ~BUF_PIN;
619df930be7Sderaadt return (ERROR);
620df930be7Sderaadt }
621df930be7Sderaadt /* FOR LOOP INIT */
622df930be7Sderaadt bp = (u_int16_t *)rbufp->page;
623df930be7Sderaadt n = *bp++;
624df930be7Sderaadt ndx = 1;
625df930be7Sderaadt off = hashp->BSIZE;
626df930be7Sderaadt } else {
627df930be7Sderaadt save_bufp->flags &= ~BUF_PIN;
628df930be7Sderaadt return (ERROR);
629df930be7Sderaadt }
630df930be7Sderaadt }
631df930be7Sderaadt
632df930be7Sderaadt /* Not found */
633df930be7Sderaadt switch (action) {
634df930be7Sderaadt case HASH_PUT:
635df930be7Sderaadt case HASH_PUTNEW:
636df930be7Sderaadt if (__addel(hashp, rbufp, key, val)) {
637df930be7Sderaadt save_bufp->flags &= ~BUF_PIN;
638df930be7Sderaadt return (ERROR);
639df930be7Sderaadt } else {
640df930be7Sderaadt save_bufp->flags &= ~BUF_PIN;
641df930be7Sderaadt return (SUCCESS);
642df930be7Sderaadt }
643df930be7Sderaadt case HASH_GET:
644df930be7Sderaadt case HASH_DELETE:
645df930be7Sderaadt default:
646df930be7Sderaadt save_bufp->flags &= ~BUF_PIN;
647df930be7Sderaadt return (ABNORMAL);
648df930be7Sderaadt }
649df930be7Sderaadt
650df930be7Sderaadt found:
651df930be7Sderaadt switch (action) {
652df930be7Sderaadt case HASH_PUTNEW:
653df930be7Sderaadt save_bufp->flags &= ~BUF_PIN;
654df930be7Sderaadt return (ABNORMAL);
655df930be7Sderaadt case HASH_GET:
656df930be7Sderaadt bp = (u_int16_t *)rbufp->page;
657df930be7Sderaadt if (bp[ndx + 1] < REAL_KEY) {
658df930be7Sderaadt if (__big_return(hashp, rbufp, ndx, val, 0))
659df930be7Sderaadt return (ERROR);
660df930be7Sderaadt } else {
661df930be7Sderaadt val->data = (u_char *)rbufp->page + (int)bp[ndx + 1];
662df930be7Sderaadt val->size = bp[ndx] - bp[ndx + 1];
663df930be7Sderaadt }
664df930be7Sderaadt break;
665df930be7Sderaadt case HASH_PUT:
666df930be7Sderaadt if ((__delpair(hashp, rbufp, ndx)) ||
667df930be7Sderaadt (__addel(hashp, rbufp, key, val))) {
668df930be7Sderaadt save_bufp->flags &= ~BUF_PIN;
669df930be7Sderaadt return (ERROR);
670df930be7Sderaadt }
671df930be7Sderaadt break;
672df930be7Sderaadt case HASH_DELETE:
673df930be7Sderaadt if (__delpair(hashp, rbufp, ndx))
674df930be7Sderaadt return (ERROR);
675df930be7Sderaadt break;
676df930be7Sderaadt default:
677df930be7Sderaadt abort();
678df930be7Sderaadt }
679df930be7Sderaadt save_bufp->flags &= ~BUF_PIN;
680df930be7Sderaadt return (SUCCESS);
681df930be7Sderaadt }
682df930be7Sderaadt
683df930be7Sderaadt static int
hash_seq(const DB * dbp,DBT * key,DBT * data,u_int32_t flag)684e20a56a5Sotto hash_seq(const DB *dbp, DBT *key, DBT *data, u_int32_t flag)
685df930be7Sderaadt {
6866c51c909Smillert u_int32_t bucket;
6876c51c909Smillert BUFHEAD *bufp;
688df930be7Sderaadt HTAB *hashp;
689df930be7Sderaadt u_int16_t *bp, ndx;
690df930be7Sderaadt
691df930be7Sderaadt hashp = (HTAB *)dbp->internal;
692df930be7Sderaadt if (flag && flag != R_FIRST && flag != R_NEXT) {
693c7cc963cSmarc hashp->err = errno = EINVAL;
694df930be7Sderaadt return (ERROR);
695df930be7Sderaadt }
696df930be7Sderaadt #ifdef HASH_STATISTICS
697df930be7Sderaadt hash_accesses++;
698df930be7Sderaadt #endif
699df930be7Sderaadt if ((hashp->cbucket < 0) || (flag == R_FIRST)) {
700df930be7Sderaadt hashp->cbucket = 0;
701df930be7Sderaadt hashp->cndx = 1;
702df930be7Sderaadt hashp->cpage = NULL;
703df930be7Sderaadt }
704344d848dSmillert next_bucket:
705df930be7Sderaadt for (bp = NULL; !bp || !bp[0]; ) {
706df930be7Sderaadt if (!(bufp = hashp->cpage)) {
707df930be7Sderaadt for (bucket = hashp->cbucket;
708df930be7Sderaadt bucket <= hashp->MAX_BUCKET;
709df930be7Sderaadt bucket++, hashp->cndx = 1) {
710df930be7Sderaadt bufp = __get_buf(hashp, bucket, NULL, 0);
711df930be7Sderaadt if (!bufp)
712df930be7Sderaadt return (ERROR);
713df930be7Sderaadt hashp->cpage = bufp;
714df930be7Sderaadt bp = (u_int16_t *)bufp->page;
715df930be7Sderaadt if (bp[0])
716df930be7Sderaadt break;
717df930be7Sderaadt }
718df930be7Sderaadt hashp->cbucket = bucket;
719df930be7Sderaadt if (hashp->cbucket > hashp->MAX_BUCKET) {
720df930be7Sderaadt hashp->cbucket = -1;
721df930be7Sderaadt return (ABNORMAL);
722df930be7Sderaadt }
723344d848dSmillert } else {
724df930be7Sderaadt bp = (u_int16_t *)hashp->cpage->page;
725344d848dSmillert if (flag == R_NEXT) {
726344d848dSmillert hashp->cndx += 2;
727344d848dSmillert if (hashp->cndx > bp[0]) {
728344d848dSmillert hashp->cpage = NULL;
729344d848dSmillert hashp->cbucket++;
730344d848dSmillert hashp->cndx = 1;
731344d848dSmillert goto next_bucket;
732344d848dSmillert }
733344d848dSmillert }
734344d848dSmillert }
735df930be7Sderaadt
736df930be7Sderaadt #ifdef DEBUG
737df930be7Sderaadt assert(bp);
738df930be7Sderaadt assert(bufp);
739df930be7Sderaadt #endif
740df930be7Sderaadt while (bp[hashp->cndx + 1] == OVFLPAGE) {
741df930be7Sderaadt bufp = hashp->cpage =
742df930be7Sderaadt __get_buf(hashp, bp[hashp->cndx], bufp, 0);
743df930be7Sderaadt if (!bufp)
744df930be7Sderaadt return (ERROR);
745df930be7Sderaadt bp = (u_int16_t *)(bufp->page);
746df930be7Sderaadt hashp->cndx = 1;
747df930be7Sderaadt }
748df930be7Sderaadt if (!bp[0]) {
749df930be7Sderaadt hashp->cpage = NULL;
750df930be7Sderaadt ++hashp->cbucket;
751df930be7Sderaadt }
752df930be7Sderaadt }
753df930be7Sderaadt ndx = hashp->cndx;
754df930be7Sderaadt if (bp[ndx + 1] < REAL_KEY) {
755df930be7Sderaadt if (__big_keydata(hashp, bufp, key, data, 1))
756df930be7Sderaadt return (ERROR);
757df930be7Sderaadt } else {
75807f46334Sotto if (hashp->cpage == 0)
75907f46334Sotto return (ERROR);
760df930be7Sderaadt key->data = (u_char *)hashp->cpage->page + bp[ndx];
761df930be7Sderaadt key->size = (ndx > 1 ? bp[ndx - 1] : hashp->BSIZE) - bp[ndx];
762df930be7Sderaadt data->data = (u_char *)hashp->cpage->page + bp[ndx + 1];
763df930be7Sderaadt data->size = bp[ndx] - bp[ndx + 1];
764df930be7Sderaadt }
765df930be7Sderaadt return (SUCCESS);
766df930be7Sderaadt }
767df930be7Sderaadt
768df930be7Sderaadt /********************************* UTILITIES ************************/
769df930be7Sderaadt
770df930be7Sderaadt /*
771df930be7Sderaadt * Returns:
772df930be7Sderaadt * 0 ==> OK
773df930be7Sderaadt * -1 ==> Error
774df930be7Sderaadt */
775e20a56a5Sotto int
__expand_table(HTAB * hashp)776e20a56a5Sotto __expand_table(HTAB *hashp)
777df930be7Sderaadt {
778df930be7Sderaadt u_int32_t old_bucket, new_bucket;
779df930be7Sderaadt int dirsize, new_segnum, spare_ndx;
780df930be7Sderaadt
781df930be7Sderaadt #ifdef HASH_STATISTICS
782df930be7Sderaadt hash_expansions++;
783df930be7Sderaadt #endif
784df930be7Sderaadt new_bucket = ++hashp->MAX_BUCKET;
785df930be7Sderaadt old_bucket = (hashp->MAX_BUCKET & hashp->LOW_MASK);
786df930be7Sderaadt
787df930be7Sderaadt new_segnum = new_bucket >> hashp->SSHIFT;
788df930be7Sderaadt
789df930be7Sderaadt /* Check if we need a new segment */
790df930be7Sderaadt if (new_segnum >= hashp->nsegs) {
791df930be7Sderaadt /* Check if we need to expand directory */
792df930be7Sderaadt if (new_segnum >= hashp->DSIZE) {
793df930be7Sderaadt /* Reallocate directory */
794df930be7Sderaadt dirsize = hashp->DSIZE * sizeof(SEGMENT *);
795df930be7Sderaadt if (!hash_realloc(&hashp->dir, dirsize, dirsize << 1))
796df930be7Sderaadt return (-1);
797df930be7Sderaadt hashp->DSIZE = dirsize << 1;
798df930be7Sderaadt }
799df930be7Sderaadt if ((hashp->dir[new_segnum] =
800df930be7Sderaadt (SEGMENT)calloc(hashp->SGSIZE, sizeof(SEGMENT))) == NULL)
801df930be7Sderaadt return (-1);
802df930be7Sderaadt hashp->exsegs++;
803df930be7Sderaadt hashp->nsegs++;
804df930be7Sderaadt }
805df930be7Sderaadt /*
806df930be7Sderaadt * If the split point is increasing (MAX_BUCKET's log base 2
807df930be7Sderaadt * * increases), we need to copy the current contents of the spare
808df930be7Sderaadt * split bucket to the next bucket.
809df930be7Sderaadt */
810df930be7Sderaadt spare_ndx = __log2(hashp->MAX_BUCKET + 1);
811df930be7Sderaadt if (spare_ndx > hashp->OVFL_POINT) {
812df930be7Sderaadt hashp->SPARES[spare_ndx] = hashp->SPARES[hashp->OVFL_POINT];
813df930be7Sderaadt hashp->OVFL_POINT = spare_ndx;
814df930be7Sderaadt }
815df930be7Sderaadt
816df930be7Sderaadt if (new_bucket > hashp->HIGH_MASK) {
817df930be7Sderaadt /* Starting a new doubling */
818df930be7Sderaadt hashp->LOW_MASK = hashp->HIGH_MASK;
819df930be7Sderaadt hashp->HIGH_MASK = new_bucket | hashp->LOW_MASK;
820df930be7Sderaadt }
821df930be7Sderaadt /* Relocate records to the new bucket */
822df930be7Sderaadt return (__split_page(hashp, old_bucket, new_bucket));
823df930be7Sderaadt }
824df930be7Sderaadt
825df930be7Sderaadt /*
826df930be7Sderaadt * If realloc guarantees that the pointer is not destroyed if the realloc
827df930be7Sderaadt * fails, then this routine can go away.
828df930be7Sderaadt */
829df930be7Sderaadt static void *
hash_realloc(SEGMENT ** p_ptr,int oldsize,int newsize)830e20a56a5Sotto hash_realloc(SEGMENT **p_ptr, int oldsize, int newsize)
831df930be7Sderaadt {
8326c51c909Smillert void *p;
833df930be7Sderaadt
834dfa5a4f6Smillert if ((p = malloc(newsize))) {
835df930be7Sderaadt memmove(p, *p_ptr, oldsize);
836df930be7Sderaadt memset((char *)p + oldsize, 0, newsize - oldsize);
837df930be7Sderaadt free(*p_ptr);
838df930be7Sderaadt *p_ptr = p;
839df930be7Sderaadt }
840df930be7Sderaadt return (p);
841df930be7Sderaadt }
842df930be7Sderaadt
843e20a56a5Sotto u_int32_t
__call_hash(HTAB * hashp,char * k,int len)844e20a56a5Sotto __call_hash(HTAB *hashp, char *k, int len)
845df930be7Sderaadt {
846df930be7Sderaadt int n, bucket;
847df930be7Sderaadt
848df930be7Sderaadt n = hashp->hash(k, len);
849df930be7Sderaadt bucket = n & hashp->HIGH_MASK;
850df930be7Sderaadt if (bucket > hashp->MAX_BUCKET)
851df930be7Sderaadt bucket = bucket & hashp->LOW_MASK;
852df930be7Sderaadt return (bucket);
853df930be7Sderaadt }
854df930be7Sderaadt
855df930be7Sderaadt /*
856df930be7Sderaadt * Allocate segment table. On error, destroy the table and set errno.
857df930be7Sderaadt *
858df930be7Sderaadt * Returns 0 on success
859df930be7Sderaadt */
860df930be7Sderaadt static int
alloc_segs(HTAB * hashp,int nsegs)861e20a56a5Sotto alloc_segs(HTAB *hashp, int nsegs)
862df930be7Sderaadt {
8636c51c909Smillert int i;
8646c51c909Smillert SEGMENT store;
865df930be7Sderaadt
866df930be7Sderaadt int save_errno;
867df930be7Sderaadt
868df930be7Sderaadt if ((hashp->dir =
869df930be7Sderaadt (SEGMENT *)calloc(hashp->DSIZE, sizeof(SEGMENT *))) == NULL) {
870df930be7Sderaadt save_errno = errno;
871df930be7Sderaadt (void)hdestroy(hashp);
872df930be7Sderaadt errno = save_errno;
873df930be7Sderaadt return (-1);
874df930be7Sderaadt }
87507f46334Sotto hashp->nsegs = nsegs;
87607f46334Sotto if (nsegs == 0)
87707f46334Sotto return (0);
878df930be7Sderaadt /* Allocate segments */
87907f46334Sotto if ((store = (SEGMENT)calloc(nsegs << hashp->SSHIFT,
88007f46334Sotto sizeof(SEGMENT))) == NULL) {
881df930be7Sderaadt save_errno = errno;
882df930be7Sderaadt (void)hdestroy(hashp);
883df930be7Sderaadt errno = save_errno;
884df930be7Sderaadt return (-1);
885df930be7Sderaadt }
88607f46334Sotto for (i = 0; i < nsegs; i++)
887df930be7Sderaadt hashp->dir[i] = &store[i << hashp->SSHIFT];
888df930be7Sderaadt return (0);
889df930be7Sderaadt }
890df930be7Sderaadt
891df930be7Sderaadt #if BYTE_ORDER == LITTLE_ENDIAN
892df930be7Sderaadt /*
893df930be7Sderaadt * Hashp->hdr needs to be byteswapped.
894df930be7Sderaadt */
895df930be7Sderaadt static void
swap_header_copy(HASHHDR * srcp,HASHHDR * destp)896e20a56a5Sotto swap_header_copy(HASHHDR *srcp, HASHHDR *destp)
897df930be7Sderaadt {
898df930be7Sderaadt int i;
899df930be7Sderaadt
900df930be7Sderaadt P_32_COPY(srcp->magic, destp->magic);
901df930be7Sderaadt P_32_COPY(srcp->version, destp->version);
902df930be7Sderaadt P_32_COPY(srcp->lorder, destp->lorder);
903df930be7Sderaadt P_32_COPY(srcp->bsize, destp->bsize);
904df930be7Sderaadt P_32_COPY(srcp->bshift, destp->bshift);
905df930be7Sderaadt P_32_COPY(srcp->dsize, destp->dsize);
906df930be7Sderaadt P_32_COPY(srcp->ssize, destp->ssize);
907df930be7Sderaadt P_32_COPY(srcp->sshift, destp->sshift);
908df930be7Sderaadt P_32_COPY(srcp->ovfl_point, destp->ovfl_point);
909df930be7Sderaadt P_32_COPY(srcp->last_freed, destp->last_freed);
910df930be7Sderaadt P_32_COPY(srcp->max_bucket, destp->max_bucket);
911df930be7Sderaadt P_32_COPY(srcp->high_mask, destp->high_mask);
912df930be7Sderaadt P_32_COPY(srcp->low_mask, destp->low_mask);
913df930be7Sderaadt P_32_COPY(srcp->ffactor, destp->ffactor);
914df930be7Sderaadt P_32_COPY(srcp->nkeys, destp->nkeys);
915df930be7Sderaadt P_32_COPY(srcp->hdrpages, destp->hdrpages);
916df930be7Sderaadt P_32_COPY(srcp->h_charkey, destp->h_charkey);
917df930be7Sderaadt for (i = 0; i < NCACHED; i++) {
918df930be7Sderaadt P_32_COPY(srcp->spares[i], destp->spares[i]);
919df930be7Sderaadt P_16_COPY(srcp->bitmaps[i], destp->bitmaps[i]);
920df930be7Sderaadt }
921df930be7Sderaadt }
922df930be7Sderaadt
923df930be7Sderaadt static void
swap_header(HTAB * hashp)924e20a56a5Sotto swap_header(HTAB *hashp)
925df930be7Sderaadt {
926df930be7Sderaadt HASHHDR *hdrp;
927df930be7Sderaadt int i;
928df930be7Sderaadt
929df930be7Sderaadt hdrp = &hashp->hdr;
930df930be7Sderaadt
931df930be7Sderaadt M_32_SWAP(hdrp->magic);
932df930be7Sderaadt M_32_SWAP(hdrp->version);
933df930be7Sderaadt M_32_SWAP(hdrp->lorder);
934df930be7Sderaadt M_32_SWAP(hdrp->bsize);
935df930be7Sderaadt M_32_SWAP(hdrp->bshift);
936df930be7Sderaadt M_32_SWAP(hdrp->dsize);
937df930be7Sderaadt M_32_SWAP(hdrp->ssize);
938df930be7Sderaadt M_32_SWAP(hdrp->sshift);
939df930be7Sderaadt M_32_SWAP(hdrp->ovfl_point);
940df930be7Sderaadt M_32_SWAP(hdrp->last_freed);
941df930be7Sderaadt M_32_SWAP(hdrp->max_bucket);
942df930be7Sderaadt M_32_SWAP(hdrp->high_mask);
943df930be7Sderaadt M_32_SWAP(hdrp->low_mask);
944df930be7Sderaadt M_32_SWAP(hdrp->ffactor);
945df930be7Sderaadt M_32_SWAP(hdrp->nkeys);
946df930be7Sderaadt M_32_SWAP(hdrp->hdrpages);
947df930be7Sderaadt M_32_SWAP(hdrp->h_charkey);
948df930be7Sderaadt for (i = 0; i < NCACHED; i++) {
949df930be7Sderaadt M_32_SWAP(hdrp->spares[i]);
950df930be7Sderaadt M_16_SWAP(hdrp->bitmaps[i]);
951df930be7Sderaadt }
952df930be7Sderaadt }
953df930be7Sderaadt #endif
954