158f0484fSRodney W. Grimes /*-
2*8a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause
3*8a16b7a1SPedro F. Giffuni *
4f1e396bcSPaul Traina * Copyright (c) 1990, 1993, 1994
558f0484fSRodney W. Grimes * The Regents of the University of California. All rights reserved.
658f0484fSRodney W. Grimes *
758f0484fSRodney W. Grimes * This code is derived from software contributed to Berkeley by
858f0484fSRodney W. Grimes * Margo Seltzer.
958f0484fSRodney W. Grimes *
1058f0484fSRodney W. Grimes * Redistribution and use in source and binary forms, with or without
1158f0484fSRodney W. Grimes * modification, are permitted provided that the following conditions
1258f0484fSRodney W. Grimes * are met:
1358f0484fSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright
1458f0484fSRodney W. Grimes * notice, this list of conditions and the following disclaimer.
1558f0484fSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright
1658f0484fSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the
1758f0484fSRodney W. Grimes * documentation and/or other materials provided with the distribution.
18fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors
1958f0484fSRodney W. Grimes * may be used to endorse or promote products derived from this software
2058f0484fSRodney W. Grimes * without specific prior written permission.
2158f0484fSRodney W. Grimes *
2258f0484fSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2358f0484fSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2458f0484fSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2558f0484fSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2658f0484fSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2758f0484fSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2858f0484fSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2958f0484fSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3058f0484fSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3158f0484fSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3258f0484fSRodney W. Grimes * SUCH DAMAGE.
3358f0484fSRodney W. Grimes */
3458f0484fSRodney W. Grimes
35d201fe46SDaniel Eischen #include "namespace.h"
3658f0484fSRodney W. Grimes #include <sys/param.h>
3758f0484fSRodney W. Grimes #include <sys/stat.h>
3858f0484fSRodney W. Grimes
3958f0484fSRodney W. Grimes #include <errno.h>
4058f0484fSRodney W. Grimes #include <fcntl.h>
4158f0484fSRodney W. Grimes #include <stdio.h>
4258f0484fSRodney W. Grimes #include <stdlib.h>
4358f0484fSRodney W. Grimes #include <string.h>
4458f0484fSRodney W. Grimes #include <unistd.h>
4558f0484fSRodney W. Grimes #ifdef DEBUG
4658f0484fSRodney W. Grimes #include <assert.h>
4758f0484fSRodney W. Grimes #endif
48d201fe46SDaniel Eischen #include "un-namespace.h"
4958f0484fSRodney W. Grimes
5058f0484fSRodney W. Grimes #include <db.h>
5158f0484fSRodney W. Grimes #include "hash.h"
5258f0484fSRodney W. Grimes #include "page.h"
5358f0484fSRodney W. Grimes #include "extern.h"
5458f0484fSRodney W. Grimes
55c05ac53bSDavid E. O'Brien static int alloc_segs(HTAB *, int);
56c05ac53bSDavid E. O'Brien static int flush_meta(HTAB *);
57c05ac53bSDavid E. O'Brien static int hash_access(HTAB *, ACTION, DBT *, DBT *);
58c05ac53bSDavid E. O'Brien static int hash_close(DB *);
59c05ac53bSDavid E. O'Brien static int hash_delete(const DB *, const DBT *, u_int32_t);
60c05ac53bSDavid E. O'Brien static int hash_fd(const DB *);
61c05ac53bSDavid E. O'Brien static int hash_get(const DB *, const DBT *, DBT *, u_int32_t);
62c05ac53bSDavid E. O'Brien static int hash_put(const DB *, DBT *, const DBT *, u_int32_t);
63c05ac53bSDavid E. O'Brien static void *hash_realloc(SEGMENT **, int, int);
64c05ac53bSDavid E. O'Brien static int hash_seq(const DB *, DBT *, DBT *, u_int32_t);
65c05ac53bSDavid E. O'Brien static int hash_sync(const DB *, u_int32_t);
66c05ac53bSDavid E. O'Brien static int hdestroy(HTAB *);
67f22d3eb4SXin LI static HTAB *init_hash(HTAB *, const char *, const HASHINFO *);
68c05ac53bSDavid E. O'Brien static int init_htab(HTAB *, int);
6958f0484fSRodney W. Grimes #if BYTE_ORDER == LITTLE_ENDIAN
70c05ac53bSDavid E. O'Brien static void swap_header(HTAB *);
71c05ac53bSDavid E. O'Brien static void swap_header_copy(HASHHDR *, HASHHDR *);
7258f0484fSRodney W. Grimes #endif
7358f0484fSRodney W. Grimes
7458f0484fSRodney W. Grimes /* Fast arithmetic, relying on powers of 2, */
7558f0484fSRodney W. Grimes #define MOD(x, y) ((x) & ((y) - 1))
7658f0484fSRodney W. Grimes
7758f0484fSRodney W. Grimes #define RETURN_ERROR(ERR, LOC) { save_errno = ERR; goto LOC; }
7858f0484fSRodney W. Grimes
7958f0484fSRodney W. Grimes /* Return values */
8058f0484fSRodney W. Grimes #define SUCCESS (0)
8158f0484fSRodney W. Grimes #define ERROR (-1)
8258f0484fSRodney W. Grimes #define ABNORMAL (1)
8358f0484fSRodney W. Grimes
8458f0484fSRodney W. Grimes #ifdef HASH_STATISTICS
85f1e396bcSPaul Traina int hash_accesses, hash_collisions, hash_expansions, hash_overflows;
8658f0484fSRodney W. Grimes #endif
8758f0484fSRodney W. Grimes
8858f0484fSRodney W. Grimes /************************** INTERFACE ROUTINES ***************************/
8958f0484fSRodney W. Grimes /* OPEN/CLOSE */
9058f0484fSRodney W. Grimes
910ac22237SXin LI /* ARGSUSED */
920ac22237SXin LI DB *
__hash_open(const char * file,int flags,int mode,const HASHINFO * info,int dflags)930ac22237SXin LI __hash_open(const char *file, int flags, int mode,
940ac22237SXin LI const HASHINFO *info, /* Special directives for create */
950ac22237SXin LI int dflags)
9658f0484fSRodney W. Grimes {
9758f0484fSRodney W. Grimes HTAB *hashp;
9858f0484fSRodney W. Grimes struct stat statbuf;
9958f0484fSRodney W. Grimes DB *dbp;
10058f0484fSRodney W. Grimes int bpages, hdrsize, new_table, nsegs, save_errno;
10158f0484fSRodney W. Grimes
10258f0484fSRodney W. Grimes if ((flags & O_ACCMODE) == O_WRONLY) {
10358f0484fSRodney W. Grimes errno = EINVAL;
10458f0484fSRodney W. Grimes return (NULL);
10558f0484fSRodney W. Grimes }
10658f0484fSRodney W. Grimes
10758f0484fSRodney W. Grimes if (!(hashp = (HTAB *)calloc(1, sizeof(HTAB))))
10858f0484fSRodney W. Grimes return (NULL);
10958f0484fSRodney W. Grimes hashp->fp = -1;
11058f0484fSRodney W. Grimes
11158f0484fSRodney W. Grimes /*
11258f0484fSRodney W. Grimes * Even if user wants write only, we need to be able to read
11358f0484fSRodney W. Grimes * the actual file, so we need to open it read/write. But, the
11458f0484fSRodney W. Grimes * field in the hashp structure needs to be accurate so that
11558f0484fSRodney W. Grimes * we can check accesses.
11658f0484fSRodney W. Grimes */
11758f0484fSRodney W. Grimes hashp->flags = flags;
11858f0484fSRodney W. Grimes
11958f0484fSRodney W. Grimes if (file) {
12046d71747SJilles Tjoelker if ((hashp->fp = _open(file, flags | O_CLOEXEC, mode)) == -1)
12158f0484fSRodney W. Grimes RETURN_ERROR(errno, error0);
122edcdc752SXin LI new_table = _fstat(hashp->fp, &statbuf) == 0 &&
123edcdc752SXin LI statbuf.st_size == 0 && (flags & O_ACCMODE) != O_RDONLY;
124edcdc752SXin LI } else
1251f70caceSPaul Traina new_table = 1;
1261f70caceSPaul Traina
12758f0484fSRodney W. Grimes if (new_table) {
128f22d3eb4SXin LI if (!(hashp = init_hash(hashp, file, info)))
12958f0484fSRodney W. Grimes RETURN_ERROR(errno, error1);
13058f0484fSRodney W. Grimes } else {
13158f0484fSRodney W. Grimes /* Table already exists */
13258f0484fSRodney W. Grimes if (info && info->hash)
13358f0484fSRodney W. Grimes hashp->hash = info->hash;
13458f0484fSRodney W. Grimes else
13558f0484fSRodney W. Grimes hashp->hash = __default_hash;
13658f0484fSRodney W. Grimes
1379233c4d9SJason Evans hdrsize = _read(hashp->fp, &hashp->hdr, sizeof(HASHHDR));
13858f0484fSRodney W. Grimes #if BYTE_ORDER == LITTLE_ENDIAN
13958f0484fSRodney W. Grimes swap_header(hashp);
14058f0484fSRodney W. Grimes #endif
14158f0484fSRodney W. Grimes if (hdrsize == -1)
14258f0484fSRodney W. Grimes RETURN_ERROR(errno, error1);
14358f0484fSRodney W. Grimes if (hdrsize != sizeof(HASHHDR))
14458f0484fSRodney W. Grimes RETURN_ERROR(EFTYPE, error1);
14558f0484fSRodney W. Grimes /* Verify file type, versions and hash function */
14658f0484fSRodney W. Grimes if (hashp->MAGIC != HASHMAGIC)
14758f0484fSRodney W. Grimes RETURN_ERROR(EFTYPE, error1);
14858f0484fSRodney W. Grimes #define OLDHASHVERSION 1
14958f0484fSRodney W. Grimes if (hashp->VERSION != HASHVERSION &&
15058f0484fSRodney W. Grimes hashp->VERSION != OLDHASHVERSION)
15158f0484fSRodney W. Grimes RETURN_ERROR(EFTYPE, error1);
152f60486b3SXin LI if ((int32_t)hashp->hash(CHARKEY, sizeof(CHARKEY)) != hashp->H_CHARKEY)
15358f0484fSRodney W. Grimes RETURN_ERROR(EFTYPE, error1);
15458f0484fSRodney W. Grimes /*
15558f0484fSRodney W. Grimes * Figure out how many segments we need. Max_Bucket is the
15658f0484fSRodney W. Grimes * maximum bucket number, so the number of buckets is
15758f0484fSRodney W. Grimes * max_bucket + 1.
15858f0484fSRodney W. Grimes */
159968c0b40SPedro F. Giffuni nsegs = howmany(hashp->MAX_BUCKET + 1, hashp->SGSIZE);
16058f0484fSRodney W. Grimes if (alloc_segs(hashp, nsegs))
16158f0484fSRodney W. Grimes /*
16258f0484fSRodney W. Grimes * If alloc_segs fails, table will have been destroyed
16358f0484fSRodney W. Grimes * and errno will have been set.
16458f0484fSRodney W. Grimes */
16558f0484fSRodney W. Grimes return (NULL);
16658f0484fSRodney W. Grimes /* Read in bitmaps */
16758f0484fSRodney W. Grimes bpages = (hashp->SPARES[hashp->OVFL_POINT] +
16858f0484fSRodney W. Grimes (hashp->BSIZE << BYTE_SHIFT) - 1) >>
16958f0484fSRodney W. Grimes (hashp->BSHIFT + BYTE_SHIFT);
17058f0484fSRodney W. Grimes
17158f0484fSRodney W. Grimes hashp->nmaps = bpages;
172f1e396bcSPaul Traina (void)memset(&hashp->mapp[0], 0, bpages * sizeof(u_int32_t *));
17358f0484fSRodney W. Grimes }
17458f0484fSRodney W. Grimes
17558f0484fSRodney W. Grimes /* Initialize Buffer Manager */
17658f0484fSRodney W. Grimes if (info && info->cachesize)
17758f0484fSRodney W. Grimes __buf_init(hashp, info->cachesize);
17858f0484fSRodney W. Grimes else
17958f0484fSRodney W. Grimes __buf_init(hashp, DEF_BUFSIZE);
18058f0484fSRodney W. Grimes
18158f0484fSRodney W. Grimes hashp->new_file = new_table;
18258f0484fSRodney W. Grimes hashp->save_file = file && (hashp->flags & O_RDWR);
18358f0484fSRodney W. Grimes hashp->cbucket = -1;
18458f0484fSRodney W. Grimes if (!(dbp = (DB *)malloc(sizeof(DB)))) {
18558f0484fSRodney W. Grimes save_errno = errno;
18658f0484fSRodney W. Grimes hdestroy(hashp);
18758f0484fSRodney W. Grimes errno = save_errno;
18858f0484fSRodney W. Grimes return (NULL);
18958f0484fSRodney W. Grimes }
19058f0484fSRodney W. Grimes dbp->internal = hashp;
19158f0484fSRodney W. Grimes dbp->close = hash_close;
19258f0484fSRodney W. Grimes dbp->del = hash_delete;
19358f0484fSRodney W. Grimes dbp->fd = hash_fd;
19458f0484fSRodney W. Grimes dbp->get = hash_get;
19558f0484fSRodney W. Grimes dbp->put = hash_put;
19658f0484fSRodney W. Grimes dbp->seq = hash_seq;
19758f0484fSRodney W. Grimes dbp->sync = hash_sync;
19858f0484fSRodney W. Grimes dbp->type = DB_HASH;
19958f0484fSRodney W. Grimes
20058f0484fSRodney W. Grimes #ifdef DEBUG
20158f0484fSRodney W. Grimes (void)fprintf(stderr,
202312f1851SJun Kuriyama "%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",
20358f0484fSRodney W. Grimes "init_htab:",
20458f0484fSRodney W. Grimes "TABLE POINTER ", hashp,
20558f0484fSRodney W. Grimes "BUCKET SIZE ", hashp->BSIZE,
20658f0484fSRodney W. Grimes "BUCKET SHIFT ", hashp->BSHIFT,
20758f0484fSRodney W. Grimes "DIRECTORY SIZE ", hashp->DSIZE,
20858f0484fSRodney W. Grimes "SEGMENT SIZE ", hashp->SGSIZE,
20958f0484fSRodney W. Grimes "SEGMENT SHIFT ", hashp->SSHIFT,
21058f0484fSRodney W. Grimes "FILL FACTOR ", hashp->FFACTOR,
21158f0484fSRodney W. Grimes "MAX BUCKET ", hashp->MAX_BUCKET,
21258f0484fSRodney W. Grimes "OVFL POINT ", hashp->OVFL_POINT,
21358f0484fSRodney W. Grimes "LAST FREED ", hashp->LAST_FREED,
21458f0484fSRodney W. Grimes "HIGH MASK ", hashp->HIGH_MASK,
21558f0484fSRodney W. Grimes "LOW MASK ", hashp->LOW_MASK,
21658f0484fSRodney W. Grimes "NSEGS ", hashp->nsegs,
21758f0484fSRodney W. Grimes "NKEYS ", hashp->NKEYS);
21858f0484fSRodney W. Grimes #endif
21958f0484fSRodney W. Grimes #ifdef HASH_STATISTICS
22058f0484fSRodney W. Grimes hash_overflows = hash_accesses = hash_collisions = hash_expansions = 0;
22158f0484fSRodney W. Grimes #endif
22258f0484fSRodney W. Grimes return (dbp);
22358f0484fSRodney W. Grimes
22458f0484fSRodney W. Grimes error1:
22558f0484fSRodney W. Grimes if (hashp != NULL)
2269233c4d9SJason Evans (void)_close(hashp->fp);
22758f0484fSRodney W. Grimes
22858f0484fSRodney W. Grimes error0:
22958f0484fSRodney W. Grimes free(hashp);
23058f0484fSRodney W. Grimes errno = save_errno;
23158f0484fSRodney W. Grimes return (NULL);
23258f0484fSRodney W. Grimes }
23358f0484fSRodney W. Grimes
23458f0484fSRodney W. Grimes static int
hash_close(DB * dbp)2350ac22237SXin LI hash_close(DB *dbp)
23658f0484fSRodney W. Grimes {
23758f0484fSRodney W. Grimes HTAB *hashp;
23858f0484fSRodney W. Grimes int retval;
23958f0484fSRodney W. Grimes
24058f0484fSRodney W. Grimes if (!dbp)
24158f0484fSRodney W. Grimes return (ERROR);
24258f0484fSRodney W. Grimes
24358f0484fSRodney W. Grimes hashp = (HTAB *)dbp->internal;
24458f0484fSRodney W. Grimes retval = hdestroy(hashp);
24558f0484fSRodney W. Grimes free(dbp);
24658f0484fSRodney W. Grimes return (retval);
24758f0484fSRodney W. Grimes }
24858f0484fSRodney W. Grimes
24958f0484fSRodney W. Grimes static int
hash_fd(const DB * dbp)2500ac22237SXin LI hash_fd(const DB *dbp)
25158f0484fSRodney W. Grimes {
25258f0484fSRodney W. Grimes HTAB *hashp;
25358f0484fSRodney W. Grimes
25458f0484fSRodney W. Grimes if (!dbp)
25558f0484fSRodney W. Grimes return (ERROR);
25658f0484fSRodney W. Grimes
25758f0484fSRodney W. Grimes hashp = (HTAB *)dbp->internal;
25858f0484fSRodney W. Grimes if (hashp->fp == -1) {
25958f0484fSRodney W. Grimes errno = ENOENT;
26058f0484fSRodney W. Grimes return (-1);
26158f0484fSRodney W. Grimes }
26258f0484fSRodney W. Grimes return (hashp->fp);
26358f0484fSRodney W. Grimes }
26458f0484fSRodney W. Grimes
26558f0484fSRodney W. Grimes /************************** LOCAL CREATION ROUTINES **********************/
26658f0484fSRodney W. Grimes static HTAB *
init_hash(HTAB * hashp,const char * file,const HASHINFO * info)2670ac22237SXin LI init_hash(HTAB *hashp, const char *file, const HASHINFO *info)
26858f0484fSRodney W. Grimes {
26958f0484fSRodney W. Grimes struct stat statbuf;
27058f0484fSRodney W. Grimes int nelem;
27158f0484fSRodney W. Grimes
27258f0484fSRodney W. Grimes nelem = 1;
27358f0484fSRodney W. Grimes hashp->NKEYS = 0;
27458f0484fSRodney W. Grimes hashp->LORDER = BYTE_ORDER;
27558f0484fSRodney W. Grimes hashp->BSIZE = DEF_BUCKET_SIZE;
27658f0484fSRodney W. Grimes hashp->BSHIFT = DEF_BUCKET_SHIFT;
27758f0484fSRodney W. Grimes hashp->SGSIZE = DEF_SEGSIZE;
27858f0484fSRodney W. Grimes hashp->SSHIFT = DEF_SEGSIZE_SHIFT;
27958f0484fSRodney W. Grimes hashp->DSIZE = DEF_DIRSIZE;
28058f0484fSRodney W. Grimes hashp->FFACTOR = DEF_FFACTOR;
28158f0484fSRodney W. Grimes hashp->hash = __default_hash;
28258f0484fSRodney W. Grimes memset(hashp->SPARES, 0, sizeof(hashp->SPARES));
28358f0484fSRodney W. Grimes memset(hashp->BITMAPS, 0, sizeof (hashp->BITMAPS));
28458f0484fSRodney W. Grimes
28558f0484fSRodney W. Grimes /* Fix bucket size to be optimal for file system */
28658f0484fSRodney W. Grimes if (file != NULL) {
28758f0484fSRodney W. Grimes if (stat(file, &statbuf))
28858f0484fSRodney W. Grimes return (NULL);
28958f0484fSRodney W. Grimes hashp->BSIZE = statbuf.st_blksize;
290f3c733e8SAndriy Gapon if (hashp->BSIZE > MAX_BSIZE)
291f3c733e8SAndriy Gapon hashp->BSIZE = MAX_BSIZE;
29258f0484fSRodney W. Grimes hashp->BSHIFT = __log2(hashp->BSIZE);
29358f0484fSRodney W. Grimes }
29458f0484fSRodney W. Grimes
29558f0484fSRodney W. Grimes if (info) {
29658f0484fSRodney W. Grimes if (info->bsize) {
29758f0484fSRodney W. Grimes /* Round pagesize up to power of 2 */
29858f0484fSRodney W. Grimes hashp->BSHIFT = __log2(info->bsize);
29958f0484fSRodney W. Grimes hashp->BSIZE = 1 << hashp->BSHIFT;
30058f0484fSRodney W. Grimes if (hashp->BSIZE > MAX_BSIZE) {
30158f0484fSRodney W. Grimes errno = EINVAL;
30258f0484fSRodney W. Grimes return (NULL);
30358f0484fSRodney W. Grimes }
30458f0484fSRodney W. Grimes }
30558f0484fSRodney W. Grimes if (info->ffactor)
30658f0484fSRodney W. Grimes hashp->FFACTOR = info->ffactor;
30758f0484fSRodney W. Grimes if (info->hash)
30858f0484fSRodney W. Grimes hashp->hash = info->hash;
30958f0484fSRodney W. Grimes if (info->nelem)
31058f0484fSRodney W. Grimes nelem = info->nelem;
31158f0484fSRodney W. Grimes if (info->lorder) {
31258f0484fSRodney W. Grimes if (info->lorder != BIG_ENDIAN &&
31358f0484fSRodney W. Grimes info->lorder != LITTLE_ENDIAN) {
31458f0484fSRodney W. Grimes errno = EINVAL;
31558f0484fSRodney W. Grimes return (NULL);
31658f0484fSRodney W. Grimes }
31758f0484fSRodney W. Grimes hashp->LORDER = info->lorder;
31858f0484fSRodney W. Grimes }
31958f0484fSRodney W. Grimes }
32058f0484fSRodney W. Grimes /* init_htab should destroy the table and set errno if it fails */
32158f0484fSRodney W. Grimes if (init_htab(hashp, nelem))
32258f0484fSRodney W. Grimes return (NULL);
32358f0484fSRodney W. Grimes else
32458f0484fSRodney W. Grimes return (hashp);
32558f0484fSRodney W. Grimes }
32658f0484fSRodney W. Grimes /*
32758f0484fSRodney W. Grimes * This calls alloc_segs which may run out of memory. Alloc_segs will destroy
32858f0484fSRodney W. Grimes * the table and set errno, so we just pass the error information along.
32958f0484fSRodney W. Grimes *
33058f0484fSRodney W. Grimes * Returns 0 on No Error
33158f0484fSRodney W. Grimes */
33258f0484fSRodney W. Grimes static int
init_htab(HTAB * hashp,int nelem)3330ac22237SXin LI init_htab(HTAB *hashp, int nelem)
33458f0484fSRodney W. Grimes {
335b115f257SXin LI int nbuckets, nsegs, l2;
33658f0484fSRodney W. Grimes
33758f0484fSRodney W. Grimes /*
33858f0484fSRodney W. Grimes * Divide number of elements by the fill factor and determine a
33958f0484fSRodney W. Grimes * desired number of buckets. Allocate space for the next greater
34058f0484fSRodney W. Grimes * power of two number of buckets.
34158f0484fSRodney W. Grimes */
34258f0484fSRodney W. Grimes nelem = (nelem - 1) / hashp->FFACTOR + 1;
34358f0484fSRodney W. Grimes
34458f0484fSRodney W. Grimes l2 = __log2(MAX(nelem, 2));
34558f0484fSRodney W. Grimes nbuckets = 1 << l2;
34658f0484fSRodney W. Grimes
34758f0484fSRodney W. Grimes hashp->SPARES[l2] = l2 + 1;
34858f0484fSRodney W. Grimes hashp->SPARES[l2 + 1] = l2 + 1;
34958f0484fSRodney W. Grimes hashp->OVFL_POINT = l2;
35058f0484fSRodney W. Grimes hashp->LAST_FREED = 2;
35158f0484fSRodney W. Grimes
35258f0484fSRodney W. Grimes /* First bitmap page is at: splitpoint l2 page offset 1 */
353f1e396bcSPaul Traina if (__ibitmap(hashp, OADDR_OF(l2, 1), l2 + 1, 0))
35458f0484fSRodney W. Grimes return (-1);
35558f0484fSRodney W. Grimes
35658f0484fSRodney W. Grimes hashp->MAX_BUCKET = hashp->LOW_MASK = nbuckets - 1;
35758f0484fSRodney W. Grimes hashp->HIGH_MASK = (nbuckets << 1) - 1;
35858f0484fSRodney W. Grimes hashp->HDRPAGES = ((MAX(sizeof(HASHHDR), MINHDRSIZE) - 1) >>
35958f0484fSRodney W. Grimes hashp->BSHIFT) + 1;
36058f0484fSRodney W. Grimes
36158f0484fSRodney W. Grimes nsegs = (nbuckets - 1) / hashp->SGSIZE + 1;
36258f0484fSRodney W. Grimes nsegs = 1 << __log2(nsegs);
36358f0484fSRodney W. Grimes
36458f0484fSRodney W. Grimes if (nsegs > hashp->DSIZE)
36558f0484fSRodney W. Grimes hashp->DSIZE = nsegs;
36658f0484fSRodney W. Grimes return (alloc_segs(hashp, nsegs));
36758f0484fSRodney W. Grimes }
36858f0484fSRodney W. Grimes
36958f0484fSRodney W. Grimes /********************** DESTROY/CLOSE ROUTINES ************************/
37058f0484fSRodney W. Grimes
37158f0484fSRodney W. Grimes /*
37258f0484fSRodney W. Grimes * Flushes any changes to the file if necessary and destroys the hashp
37358f0484fSRodney W. Grimes * structure, freeing all allocated space.
37458f0484fSRodney W. Grimes */
37558f0484fSRodney W. Grimes static int
hdestroy(HTAB * hashp)3760ac22237SXin LI hdestroy(HTAB *hashp)
37758f0484fSRodney W. Grimes {
37858f0484fSRodney W. Grimes int i, save_errno;
37958f0484fSRodney W. Grimes
38058f0484fSRodney W. Grimes save_errno = 0;
38158f0484fSRodney W. Grimes
38258f0484fSRodney W. Grimes #ifdef HASH_STATISTICS
38358f0484fSRodney W. Grimes (void)fprintf(stderr, "hdestroy: accesses %ld collisions %ld\n",
38458f0484fSRodney W. Grimes hash_accesses, hash_collisions);
38558f0484fSRodney W. Grimes (void)fprintf(stderr, "hdestroy: expansions %ld\n",
38658f0484fSRodney W. Grimes hash_expansions);
38758f0484fSRodney W. Grimes (void)fprintf(stderr, "hdestroy: overflows %ld\n",
38858f0484fSRodney W. Grimes hash_overflows);
38958f0484fSRodney W. Grimes (void)fprintf(stderr, "keys %ld maxp %d segmentcount %d\n",
39058f0484fSRodney W. Grimes hashp->NKEYS, hashp->MAX_BUCKET, hashp->nsegs);
39158f0484fSRodney W. Grimes
39258f0484fSRodney W. Grimes for (i = 0; i < NCACHED; i++)
39358f0484fSRodney W. Grimes (void)fprintf(stderr,
39458f0484fSRodney W. Grimes "spares[%d] = %d\n", i, hashp->SPARES[i]);
39558f0484fSRodney W. Grimes #endif
39658f0484fSRodney W. Grimes /*
39758f0484fSRodney W. Grimes * Call on buffer manager to free buffers, and if required,
39858f0484fSRodney W. Grimes * write them to disk.
39958f0484fSRodney W. Grimes */
40058f0484fSRodney W. Grimes if (__buf_free(hashp, 1, hashp->save_file))
40158f0484fSRodney W. Grimes save_errno = errno;
40258f0484fSRodney W. Grimes if (hashp->dir) {
40358f0484fSRodney W. Grimes free(*hashp->dir); /* Free initial segments */
40458f0484fSRodney W. Grimes /* Free extra segments */
40558f0484fSRodney W. Grimes while (hashp->exsegs--)
40658f0484fSRodney W. Grimes free(hashp->dir[--hashp->nsegs]);
40758f0484fSRodney W. Grimes free(hashp->dir);
40858f0484fSRodney W. Grimes }
40958f0484fSRodney W. Grimes if (flush_meta(hashp) && !save_errno)
41058f0484fSRodney W. Grimes save_errno = errno;
41158f0484fSRodney W. Grimes /* Free Bigmaps */
41258f0484fSRodney W. Grimes for (i = 0; i < hashp->nmaps; i++)
41358f0484fSRodney W. Grimes if (hashp->mapp[i])
41458f0484fSRodney W. Grimes free(hashp->mapp[i]);
4156c90d46eSXin LI if (hashp->tmp_key)
4166c90d46eSXin LI free(hashp->tmp_key);
4176c90d46eSXin LI if (hashp->tmp_buf)
4186c90d46eSXin LI free(hashp->tmp_buf);
41958f0484fSRodney W. Grimes
420efb7dae2SDavid Malone if (hashp->fp != -1) {
42115719ec4SBryan Drewery if (hashp->save_file)
422efb7dae2SDavid Malone (void)_fsync(hashp->fp);
4239233c4d9SJason Evans (void)_close(hashp->fp);
424efb7dae2SDavid Malone }
42558f0484fSRodney W. Grimes
42658f0484fSRodney W. Grimes free(hashp);
42758f0484fSRodney W. Grimes
42858f0484fSRodney W. Grimes if (save_errno) {
42958f0484fSRodney W. Grimes errno = save_errno;
43058f0484fSRodney W. Grimes return (ERROR);
43158f0484fSRodney W. Grimes }
43258f0484fSRodney W. Grimes return (SUCCESS);
43358f0484fSRodney W. Grimes }
43458f0484fSRodney W. Grimes /*
43558f0484fSRodney W. Grimes * Write modified pages to disk
43658f0484fSRodney W. Grimes *
43758f0484fSRodney W. Grimes * Returns:
43858f0484fSRodney W. Grimes * 0 == OK
43958f0484fSRodney W. Grimes * -1 ERROR
44058f0484fSRodney W. Grimes */
44158f0484fSRodney W. Grimes static int
hash_sync(const DB * dbp,u_int32_t flags)4420ac22237SXin LI hash_sync(const DB *dbp, u_int32_t flags)
44358f0484fSRodney W. Grimes {
44458f0484fSRodney W. Grimes HTAB *hashp;
44558f0484fSRodney W. Grimes
44658f0484fSRodney W. Grimes if (flags != 0) {
44758f0484fSRodney W. Grimes errno = EINVAL;
44858f0484fSRodney W. Grimes return (ERROR);
44958f0484fSRodney W. Grimes }
45058f0484fSRodney W. Grimes
45158f0484fSRodney W. Grimes if (!dbp)
45258f0484fSRodney W. Grimes return (ERROR);
45358f0484fSRodney W. Grimes
45458f0484fSRodney W. Grimes hashp = (HTAB *)dbp->internal;
45558f0484fSRodney W. Grimes if (!hashp->save_file)
45658f0484fSRodney W. Grimes return (0);
45758f0484fSRodney W. Grimes if (__buf_free(hashp, 0, 1) || flush_meta(hashp))
45858f0484fSRodney W. Grimes return (ERROR);
459efb7dae2SDavid Malone if (hashp->fp != -1 && _fsync(hashp->fp) != 0)
460efb7dae2SDavid Malone return (ERROR);
46158f0484fSRodney W. Grimes hashp->new_file = 0;
46258f0484fSRodney W. Grimes return (0);
46358f0484fSRodney W. Grimes }
46458f0484fSRodney W. Grimes
46558f0484fSRodney W. Grimes /*
46658f0484fSRodney W. Grimes * Returns:
46758f0484fSRodney W. Grimes * 0 == OK
46858f0484fSRodney W. Grimes * -1 indicates that errno should be set
46958f0484fSRodney W. Grimes */
47058f0484fSRodney W. Grimes static int
flush_meta(HTAB * hashp)4710ac22237SXin LI flush_meta(HTAB *hashp)
47258f0484fSRodney W. Grimes {
47358f0484fSRodney W. Grimes HASHHDR *whdrp;
47458f0484fSRodney W. Grimes #if BYTE_ORDER == LITTLE_ENDIAN
47558f0484fSRodney W. Grimes HASHHDR whdr;
47658f0484fSRodney W. Grimes #endif
47758f0484fSRodney W. Grimes int fp, i, wsize;
47858f0484fSRodney W. Grimes
47958f0484fSRodney W. Grimes if (!hashp->save_file)
48058f0484fSRodney W. Grimes return (0);
48158f0484fSRodney W. Grimes hashp->MAGIC = HASHMAGIC;
48258f0484fSRodney W. Grimes hashp->VERSION = HASHVERSION;
48358f0484fSRodney W. Grimes hashp->H_CHARKEY = hashp->hash(CHARKEY, sizeof(CHARKEY));
48458f0484fSRodney W. Grimes
48558f0484fSRodney W. Grimes fp = hashp->fp;
48658f0484fSRodney W. Grimes whdrp = &hashp->hdr;
48758f0484fSRodney W. Grimes #if BYTE_ORDER == LITTLE_ENDIAN
48858f0484fSRodney W. Grimes whdrp = &whdr;
48958f0484fSRodney W. Grimes swap_header_copy(&hashp->hdr, whdrp);
49058f0484fSRodney W. Grimes #endif
491d3b2afadSXin LI if ((wsize = pwrite(fp, whdrp, sizeof(HASHHDR), (off_t)0)) == -1)
49258f0484fSRodney W. Grimes return (-1);
49358f0484fSRodney W. Grimes else
49458f0484fSRodney W. Grimes if (wsize != sizeof(HASHHDR)) {
49558f0484fSRodney W. Grimes errno = EFTYPE;
496f70177e7SJulian Elischer hashp->error = errno;
49758f0484fSRodney W. Grimes return (-1);
49858f0484fSRodney W. Grimes }
49958f0484fSRodney W. Grimes for (i = 0; i < NCACHED; i++)
50058f0484fSRodney W. Grimes if (hashp->mapp[i])
50158f0484fSRodney W. Grimes if (__put_page(hashp, (char *)hashp->mapp[i],
50258f0484fSRodney W. Grimes hashp->BITMAPS[i], 0, 1))
50358f0484fSRodney W. Grimes return (-1);
50458f0484fSRodney W. Grimes return (0);
50558f0484fSRodney W. Grimes }
50658f0484fSRodney W. Grimes
50758f0484fSRodney W. Grimes /*******************************SEARCH ROUTINES *****************************/
50858f0484fSRodney W. Grimes /*
50958f0484fSRodney W. Grimes * All the access routines return
51058f0484fSRodney W. Grimes *
51158f0484fSRodney W. Grimes * Returns:
51258f0484fSRodney W. Grimes * 0 on SUCCESS
51358f0484fSRodney W. Grimes * 1 to indicate an external ERROR (i.e. key not found, etc)
51458f0484fSRodney W. Grimes * -1 to indicate an internal ERROR (i.e. out of memory, etc)
51558f0484fSRodney W. Grimes */
51658f0484fSRodney W. Grimes static int
hash_get(const DB * dbp,const DBT * key,DBT * data,u_int32_t flag)5170ac22237SXin LI hash_get(const DB *dbp, const DBT *key, DBT *data, u_int32_t flag)
51858f0484fSRodney W. Grimes {
51958f0484fSRodney W. Grimes HTAB *hashp;
52058f0484fSRodney W. Grimes
52158f0484fSRodney W. Grimes hashp = (HTAB *)dbp->internal;
52258f0484fSRodney W. Grimes if (flag) {
523f70177e7SJulian Elischer hashp->error = errno = EINVAL;
52458f0484fSRodney W. Grimes return (ERROR);
52558f0484fSRodney W. Grimes }
52658f0484fSRodney W. Grimes return (hash_access(hashp, HASH_GET, (DBT *)key, data));
52758f0484fSRodney W. Grimes }
52858f0484fSRodney W. Grimes
52958f0484fSRodney W. Grimes static int
hash_put(const DB * dbp,DBT * key,const DBT * data,u_int32_t flag)5300ac22237SXin LI hash_put(const DB *dbp, DBT *key, const DBT *data, u_int32_t flag)
53158f0484fSRodney W. Grimes {
53258f0484fSRodney W. Grimes HTAB *hashp;
53358f0484fSRodney W. Grimes
53458f0484fSRodney W. Grimes hashp = (HTAB *)dbp->internal;
53558f0484fSRodney W. Grimes if (flag && flag != R_NOOVERWRITE) {
536213bceeeSXin LI hashp->error = errno = EINVAL;
53758f0484fSRodney W. Grimes return (ERROR);
53858f0484fSRodney W. Grimes }
53958f0484fSRodney W. Grimes if ((hashp->flags & O_ACCMODE) == O_RDONLY) {
540f70177e7SJulian Elischer hashp->error = errno = EPERM;
54158f0484fSRodney W. Grimes return (ERROR);
54258f0484fSRodney W. Grimes }
54358f0484fSRodney W. Grimes return (hash_access(hashp, flag == R_NOOVERWRITE ?
54458f0484fSRodney W. Grimes HASH_PUTNEW : HASH_PUT, (DBT *)key, (DBT *)data));
54558f0484fSRodney W. Grimes }
54658f0484fSRodney W. Grimes
54758f0484fSRodney W. Grimes static int
hash_delete(const DB * dbp,const DBT * key,u_int32_t flag)5480ac22237SXin LI hash_delete(const DB *dbp, const DBT *key,
5490ac22237SXin LI u_int32_t flag) /* Ignored */
55058f0484fSRodney W. Grimes {
55158f0484fSRodney W. Grimes HTAB *hashp;
55258f0484fSRodney W. Grimes
55358f0484fSRodney W. Grimes hashp = (HTAB *)dbp->internal;
55458f0484fSRodney W. Grimes if (flag && flag != R_CURSOR) {
555f70177e7SJulian Elischer hashp->error = errno = EINVAL;
55658f0484fSRodney W. Grimes return (ERROR);
55758f0484fSRodney W. Grimes }
55858f0484fSRodney W. Grimes if ((hashp->flags & O_ACCMODE) == O_RDONLY) {
559f70177e7SJulian Elischer hashp->error = errno = EPERM;
56058f0484fSRodney W. Grimes return (ERROR);
56158f0484fSRodney W. Grimes }
56258f0484fSRodney W. Grimes return (hash_access(hashp, HASH_DELETE, (DBT *)key, NULL));
56358f0484fSRodney W. Grimes }
56458f0484fSRodney W. Grimes
56558f0484fSRodney W. Grimes /*
56658f0484fSRodney W. Grimes * Assume that hashp has been set in wrapper routine.
56758f0484fSRodney W. Grimes */
56858f0484fSRodney W. Grimes static int
hash_access(HTAB * hashp,ACTION action,DBT * key,DBT * val)5690ac22237SXin LI hash_access(HTAB *hashp, ACTION action, DBT *key, DBT *val)
57058f0484fSRodney W. Grimes {
5718fb3f3f6SDavid E. O'Brien BUFHEAD *rbufp;
57258f0484fSRodney W. Grimes BUFHEAD *bufp, *save_bufp;
5738fb3f3f6SDavid E. O'Brien u_int16_t *bp;
5748fb3f3f6SDavid E. O'Brien int n, ndx, off, size;
5758fb3f3f6SDavid E. O'Brien char *kp;
576f1e396bcSPaul Traina u_int16_t pageno;
57758f0484fSRodney W. Grimes
57858f0484fSRodney W. Grimes #ifdef HASH_STATISTICS
57958f0484fSRodney W. Grimes hash_accesses++;
58058f0484fSRodney W. Grimes #endif
58158f0484fSRodney W. Grimes
58258f0484fSRodney W. Grimes off = hashp->BSIZE;
58358f0484fSRodney W. Grimes size = key->size;
58458f0484fSRodney W. Grimes kp = (char *)key->data;
58558f0484fSRodney W. Grimes rbufp = __get_buf(hashp, __call_hash(hashp, kp, size), NULL, 0);
58658f0484fSRodney W. Grimes if (!rbufp)
58758f0484fSRodney W. Grimes return (ERROR);
58858f0484fSRodney W. Grimes save_bufp = rbufp;
58958f0484fSRodney W. Grimes
59058f0484fSRodney W. Grimes /* Pin the bucket chain */
59158f0484fSRodney W. Grimes rbufp->flags |= BUF_PIN;
592f1e396bcSPaul Traina for (bp = (u_int16_t *)rbufp->page, n = *bp++, ndx = 1; ndx < n;)
59358f0484fSRodney W. Grimes if (bp[1] >= REAL_KEY) {
59458f0484fSRodney W. Grimes /* Real key/data pair */
59558f0484fSRodney W. Grimes if (size == off - *bp &&
59658f0484fSRodney W. Grimes memcmp(kp, rbufp->page + *bp, size) == 0)
59758f0484fSRodney W. Grimes goto found;
59858f0484fSRodney W. Grimes off = bp[1];
59958f0484fSRodney W. Grimes #ifdef HASH_STATISTICS
60058f0484fSRodney W. Grimes hash_collisions++;
60158f0484fSRodney W. Grimes #endif
60258f0484fSRodney W. Grimes bp += 2;
60358f0484fSRodney W. Grimes ndx += 2;
60458f0484fSRodney W. Grimes } else if (bp[1] == OVFLPAGE) {
60558f0484fSRodney W. Grimes rbufp = __get_buf(hashp, *bp, rbufp, 0);
60658f0484fSRodney W. Grimes if (!rbufp) {
60758f0484fSRodney W. Grimes save_bufp->flags &= ~BUF_PIN;
60858f0484fSRodney W. Grimes return (ERROR);
60958f0484fSRodney W. Grimes }
61058f0484fSRodney W. Grimes /* FOR LOOP INIT */
611f1e396bcSPaul Traina bp = (u_int16_t *)rbufp->page;
61258f0484fSRodney W. Grimes n = *bp++;
61358f0484fSRodney W. Grimes ndx = 1;
61458f0484fSRodney W. Grimes off = hashp->BSIZE;
61558f0484fSRodney W. Grimes } else if (bp[1] < REAL_KEY) {
61658f0484fSRodney W. Grimes if ((ndx =
61758f0484fSRodney W. Grimes __find_bigpair(hashp, rbufp, ndx, kp, size)) > 0)
61858f0484fSRodney W. Grimes goto found;
61958f0484fSRodney W. Grimes if (ndx == -2) {
62058f0484fSRodney W. Grimes bufp = rbufp;
62158f0484fSRodney W. Grimes if (!(pageno =
62258f0484fSRodney W. Grimes __find_last_page(hashp, &bufp))) {
62358f0484fSRodney W. Grimes ndx = 0;
62458f0484fSRodney W. Grimes rbufp = bufp;
62558f0484fSRodney W. Grimes break; /* FOR */
62658f0484fSRodney W. Grimes }
62758f0484fSRodney W. Grimes rbufp = __get_buf(hashp, pageno, bufp, 0);
62858f0484fSRodney W. Grimes if (!rbufp) {
62958f0484fSRodney W. Grimes save_bufp->flags &= ~BUF_PIN;
63058f0484fSRodney W. Grimes return (ERROR);
63158f0484fSRodney W. Grimes }
63258f0484fSRodney W. Grimes /* FOR LOOP INIT */
633f1e396bcSPaul Traina bp = (u_int16_t *)rbufp->page;
63458f0484fSRodney W. Grimes n = *bp++;
63558f0484fSRodney W. Grimes ndx = 1;
63658f0484fSRodney W. Grimes off = hashp->BSIZE;
63758f0484fSRodney W. Grimes } else {
63858f0484fSRodney W. Grimes save_bufp->flags &= ~BUF_PIN;
63958f0484fSRodney W. Grimes return (ERROR);
64058f0484fSRodney W. Grimes }
64158f0484fSRodney W. Grimes }
64258f0484fSRodney W. Grimes
64358f0484fSRodney W. Grimes /* Not found */
64458f0484fSRodney W. Grimes switch (action) {
64558f0484fSRodney W. Grimes case HASH_PUT:
64658f0484fSRodney W. Grimes case HASH_PUTNEW:
64758f0484fSRodney W. Grimes if (__addel(hashp, rbufp, key, val)) {
64858f0484fSRodney W. Grimes save_bufp->flags &= ~BUF_PIN;
64958f0484fSRodney W. Grimes return (ERROR);
65058f0484fSRodney W. Grimes } else {
65158f0484fSRodney W. Grimes save_bufp->flags &= ~BUF_PIN;
65258f0484fSRodney W. Grimes return (SUCCESS);
65358f0484fSRodney W. Grimes }
65458f0484fSRodney W. Grimes case HASH_GET:
65558f0484fSRodney W. Grimes case HASH_DELETE:
65658f0484fSRodney W. Grimes default:
65758f0484fSRodney W. Grimes save_bufp->flags &= ~BUF_PIN;
65858f0484fSRodney W. Grimes return (ABNORMAL);
65958f0484fSRodney W. Grimes }
66058f0484fSRodney W. Grimes
66158f0484fSRodney W. Grimes found:
66258f0484fSRodney W. Grimes switch (action) {
66358f0484fSRodney W. Grimes case HASH_PUTNEW:
66458f0484fSRodney W. Grimes save_bufp->flags &= ~BUF_PIN;
66558f0484fSRodney W. Grimes return (ABNORMAL);
66658f0484fSRodney W. Grimes case HASH_GET:
667f1e396bcSPaul Traina bp = (u_int16_t *)rbufp->page;
66858f0484fSRodney W. Grimes if (bp[ndx + 1] < REAL_KEY) {
66958f0484fSRodney W. Grimes if (__big_return(hashp, rbufp, ndx, val, 0))
67058f0484fSRodney W. Grimes return (ERROR);
67158f0484fSRodney W. Grimes } else {
67258f0484fSRodney W. Grimes val->data = (u_char *)rbufp->page + (int)bp[ndx + 1];
67358f0484fSRodney W. Grimes val->size = bp[ndx] - bp[ndx + 1];
67458f0484fSRodney W. Grimes }
67558f0484fSRodney W. Grimes break;
67658f0484fSRodney W. Grimes case HASH_PUT:
67758f0484fSRodney W. Grimes if ((__delpair(hashp, rbufp, ndx)) ||
67858f0484fSRodney W. Grimes (__addel(hashp, rbufp, key, val))) {
67958f0484fSRodney W. Grimes save_bufp->flags &= ~BUF_PIN;
68058f0484fSRodney W. Grimes return (ERROR);
68158f0484fSRodney W. Grimes }
68258f0484fSRodney W. Grimes break;
68358f0484fSRodney W. Grimes case HASH_DELETE:
68458f0484fSRodney W. Grimes if (__delpair(hashp, rbufp, ndx))
68558f0484fSRodney W. Grimes return (ERROR);
68658f0484fSRodney W. Grimes break;
68758f0484fSRodney W. Grimes default:
68858f0484fSRodney W. Grimes abort();
68958f0484fSRodney W. Grimes }
69058f0484fSRodney W. Grimes save_bufp->flags &= ~BUF_PIN;
69158f0484fSRodney W. Grimes return (SUCCESS);
69258f0484fSRodney W. Grimes }
69358f0484fSRodney W. Grimes
69458f0484fSRodney W. Grimes static int
hash_seq(const DB * dbp,DBT * key,DBT * data,u_int32_t flag)6950ac22237SXin LI hash_seq(const DB *dbp, DBT *key, DBT *data, u_int32_t flag)
69658f0484fSRodney W. Grimes {
6978fb3f3f6SDavid E. O'Brien u_int32_t bucket;
6988fb3f3f6SDavid E. O'Brien BUFHEAD *bufp;
69958f0484fSRodney W. Grimes HTAB *hashp;
700f1e396bcSPaul Traina u_int16_t *bp, ndx;
70158f0484fSRodney W. Grimes
70258f0484fSRodney W. Grimes hashp = (HTAB *)dbp->internal;
70358f0484fSRodney W. Grimes if (flag && flag != R_FIRST && flag != R_NEXT) {
704f70177e7SJulian Elischer hashp->error = errno = EINVAL;
70558f0484fSRodney W. Grimes return (ERROR);
70658f0484fSRodney W. Grimes }
70758f0484fSRodney W. Grimes #ifdef HASH_STATISTICS
70858f0484fSRodney W. Grimes hash_accesses++;
70958f0484fSRodney W. Grimes #endif
71058f0484fSRodney W. Grimes if ((hashp->cbucket < 0) || (flag == R_FIRST)) {
71158f0484fSRodney W. Grimes hashp->cbucket = 0;
71258f0484fSRodney W. Grimes hashp->cndx = 1;
71358f0484fSRodney W. Grimes hashp->cpage = NULL;
71458f0484fSRodney W. Grimes }
715213bceeeSXin LI next_bucket:
71658f0484fSRodney W. Grimes for (bp = NULL; !bp || !bp[0]; ) {
71758f0484fSRodney W. Grimes if (!(bufp = hashp->cpage)) {
71858f0484fSRodney W. Grimes for (bucket = hashp->cbucket;
71958f0484fSRodney W. Grimes bucket <= hashp->MAX_BUCKET;
72058f0484fSRodney W. Grimes bucket++, hashp->cndx = 1) {
72158f0484fSRodney W. Grimes bufp = __get_buf(hashp, bucket, NULL, 0);
72258f0484fSRodney W. Grimes if (!bufp)
72358f0484fSRodney W. Grimes return (ERROR);
72458f0484fSRodney W. Grimes hashp->cpage = bufp;
725f1e396bcSPaul Traina bp = (u_int16_t *)bufp->page;
72658f0484fSRodney W. Grimes if (bp[0])
72758f0484fSRodney W. Grimes break;
72858f0484fSRodney W. Grimes }
72958f0484fSRodney W. Grimes hashp->cbucket = bucket;
730f60486b3SXin LI if ((u_int32_t)hashp->cbucket > hashp->MAX_BUCKET) {
73158f0484fSRodney W. Grimes hashp->cbucket = -1;
73258f0484fSRodney W. Grimes return (ABNORMAL);
73358f0484fSRodney W. Grimes }
734213bceeeSXin LI } else {
735f1e396bcSPaul Traina bp = (u_int16_t *)hashp->cpage->page;
7364f0d3f44SXin LI if (flag == R_NEXT || flag == 0) {
737213bceeeSXin LI hashp->cndx += 2;
738213bceeeSXin LI if (hashp->cndx > bp[0]) {
739213bceeeSXin LI hashp->cpage = NULL;
740213bceeeSXin LI hashp->cbucket++;
741213bceeeSXin LI hashp->cndx = 1;
742213bceeeSXin LI goto next_bucket;
743213bceeeSXin LI }
744213bceeeSXin LI }
745213bceeeSXin LI }
74658f0484fSRodney W. Grimes
74758f0484fSRodney W. Grimes #ifdef DEBUG
74858f0484fSRodney W. Grimes assert(bp);
74958f0484fSRodney W. Grimes assert(bufp);
75058f0484fSRodney W. Grimes #endif
75158f0484fSRodney W. Grimes while (bp[hashp->cndx + 1] == OVFLPAGE) {
75258f0484fSRodney W. Grimes bufp = hashp->cpage =
75358f0484fSRodney W. Grimes __get_buf(hashp, bp[hashp->cndx], bufp, 0);
75458f0484fSRodney W. Grimes if (!bufp)
75558f0484fSRodney W. Grimes return (ERROR);
756f1e396bcSPaul Traina bp = (u_int16_t *)(bufp->page);
75758f0484fSRodney W. Grimes hashp->cndx = 1;
75858f0484fSRodney W. Grimes }
75958f0484fSRodney W. Grimes if (!bp[0]) {
76058f0484fSRodney W. Grimes hashp->cpage = NULL;
76158f0484fSRodney W. Grimes ++hashp->cbucket;
76258f0484fSRodney W. Grimes }
76358f0484fSRodney W. Grimes }
76458f0484fSRodney W. Grimes ndx = hashp->cndx;
76558f0484fSRodney W. Grimes if (bp[ndx + 1] < REAL_KEY) {
76658f0484fSRodney W. Grimes if (__big_keydata(hashp, bufp, key, data, 1))
76758f0484fSRodney W. Grimes return (ERROR);
76858f0484fSRodney W. Grimes } else {
769513004a2SPedro F. Giffuni if (hashp->cpage == NULL)
7706c90d46eSXin LI return (ERROR);
77158f0484fSRodney W. Grimes key->data = (u_char *)hashp->cpage->page + bp[ndx];
77258f0484fSRodney W. Grimes key->size = (ndx > 1 ? bp[ndx - 1] : hashp->BSIZE) - bp[ndx];
77358f0484fSRodney W. Grimes data->data = (u_char *)hashp->cpage->page + bp[ndx + 1];
77458f0484fSRodney W. Grimes data->size = bp[ndx] - bp[ndx + 1];
77558f0484fSRodney W. Grimes }
77658f0484fSRodney W. Grimes return (SUCCESS);
77758f0484fSRodney W. Grimes }
77858f0484fSRodney W. Grimes
77958f0484fSRodney W. Grimes /********************************* UTILITIES ************************/
78058f0484fSRodney W. Grimes
78158f0484fSRodney W. Grimes /*
78258f0484fSRodney W. Grimes * Returns:
78358f0484fSRodney W. Grimes * 0 ==> OK
78458f0484fSRodney W. Grimes * -1 ==> Error
78558f0484fSRodney W. Grimes */
7860ac22237SXin LI int
__expand_table(HTAB * hashp)7870ac22237SXin LI __expand_table(HTAB *hashp)
78858f0484fSRodney W. Grimes {
789f1e396bcSPaul Traina u_int32_t old_bucket, new_bucket;
79058f0484fSRodney W. Grimes int dirsize, new_segnum, spare_ndx;
79158f0484fSRodney W. Grimes
79258f0484fSRodney W. Grimes #ifdef HASH_STATISTICS
79358f0484fSRodney W. Grimes hash_expansions++;
79458f0484fSRodney W. Grimes #endif
79558f0484fSRodney W. Grimes new_bucket = ++hashp->MAX_BUCKET;
79658f0484fSRodney W. Grimes old_bucket = (hashp->MAX_BUCKET & hashp->LOW_MASK);
79758f0484fSRodney W. Grimes
79858f0484fSRodney W. Grimes new_segnum = new_bucket >> hashp->SSHIFT;
79958f0484fSRodney W. Grimes
80058f0484fSRodney W. Grimes /* Check if we need a new segment */
80158f0484fSRodney W. Grimes if (new_segnum >= hashp->nsegs) {
80258f0484fSRodney W. Grimes /* Check if we need to expand directory */
80358f0484fSRodney W. Grimes if (new_segnum >= hashp->DSIZE) {
80458f0484fSRodney W. Grimes /* Reallocate directory */
80558f0484fSRodney W. Grimes dirsize = hashp->DSIZE * sizeof(SEGMENT *);
80658f0484fSRodney W. Grimes if (!hash_realloc(&hashp->dir, dirsize, dirsize << 1))
80758f0484fSRodney W. Grimes return (-1);
80858f0484fSRodney W. Grimes hashp->DSIZE = dirsize << 1;
80958f0484fSRodney W. Grimes }
81058f0484fSRodney W. Grimes if ((hashp->dir[new_segnum] =
8111b81d865SPedro F. Giffuni calloc(hashp->SGSIZE, sizeof(SEGMENT))) == NULL)
81258f0484fSRodney W. Grimes return (-1);
81358f0484fSRodney W. Grimes hashp->exsegs++;
81458f0484fSRodney W. Grimes hashp->nsegs++;
81558f0484fSRodney W. Grimes }
81658f0484fSRodney W. Grimes /*
81758f0484fSRodney W. Grimes * If the split point is increasing (MAX_BUCKET's log base 2
81858f0484fSRodney W. Grimes * * increases), we need to copy the current contents of the spare
81958f0484fSRodney W. Grimes * split bucket to the next bucket.
82058f0484fSRodney W. Grimes */
82158f0484fSRodney W. Grimes spare_ndx = __log2(hashp->MAX_BUCKET + 1);
82258f0484fSRodney W. Grimes if (spare_ndx > hashp->OVFL_POINT) {
82358f0484fSRodney W. Grimes hashp->SPARES[spare_ndx] = hashp->SPARES[hashp->OVFL_POINT];
82458f0484fSRodney W. Grimes hashp->OVFL_POINT = spare_ndx;
82558f0484fSRodney W. Grimes }
82658f0484fSRodney W. Grimes
82758f0484fSRodney W. Grimes if (new_bucket > hashp->HIGH_MASK) {
82858f0484fSRodney W. Grimes /* Starting a new doubling */
82958f0484fSRodney W. Grimes hashp->LOW_MASK = hashp->HIGH_MASK;
83058f0484fSRodney W. Grimes hashp->HIGH_MASK = new_bucket | hashp->LOW_MASK;
83158f0484fSRodney W. Grimes }
83258f0484fSRodney W. Grimes /* Relocate records to the new bucket */
83358f0484fSRodney W. Grimes return (__split_page(hashp, old_bucket, new_bucket));
83458f0484fSRodney W. Grimes }
83558f0484fSRodney W. Grimes
83658f0484fSRodney W. Grimes /*
83758f0484fSRodney W. Grimes * If realloc guarantees that the pointer is not destroyed if the realloc
83858f0484fSRodney W. Grimes * fails, then this routine can go away.
83958f0484fSRodney W. Grimes */
84058f0484fSRodney W. Grimes static void *
hash_realloc(SEGMENT ** p_ptr,int oldsize,int newsize)8410ac22237SXin LI hash_realloc(SEGMENT **p_ptr, int oldsize, int newsize)
84258f0484fSRodney W. Grimes {
8438fb3f3f6SDavid E. O'Brien void *p;
84458f0484fSRodney W. Grimes
84551295a4dSJordan K. Hubbard if ( (p = malloc(newsize)) ) {
84658f0484fSRodney W. Grimes memmove(p, *p_ptr, oldsize);
84758f0484fSRodney W. Grimes memset((char *)p + oldsize, 0, newsize - oldsize);
84858f0484fSRodney W. Grimes free(*p_ptr);
84958f0484fSRodney W. Grimes *p_ptr = p;
85058f0484fSRodney W. Grimes }
85158f0484fSRodney W. Grimes return (p);
85258f0484fSRodney W. Grimes }
85358f0484fSRodney W. Grimes
8540ac22237SXin LI u_int32_t
__call_hash(HTAB * hashp,char * k,int len)8550ac22237SXin LI __call_hash(HTAB *hashp, char *k, int len)
85658f0484fSRodney W. Grimes {
857f60486b3SXin LI unsigned int n, bucket;
85858f0484fSRodney W. Grimes
85958f0484fSRodney W. Grimes n = hashp->hash(k, len);
86058f0484fSRodney W. Grimes bucket = n & hashp->HIGH_MASK;
86158f0484fSRodney W. Grimes if (bucket > hashp->MAX_BUCKET)
86258f0484fSRodney W. Grimes bucket = bucket & hashp->LOW_MASK;
86358f0484fSRodney W. Grimes return (bucket);
86458f0484fSRodney W. Grimes }
86558f0484fSRodney W. Grimes
86658f0484fSRodney W. Grimes /*
86758f0484fSRodney W. Grimes * Allocate segment table. On error, destroy the table and set errno.
86858f0484fSRodney W. Grimes *
86958f0484fSRodney W. Grimes * Returns 0 on success
87058f0484fSRodney W. Grimes */
87158f0484fSRodney W. Grimes static int
alloc_segs(HTAB * hashp,int nsegs)8720ac22237SXin LI alloc_segs(HTAB *hashp, int nsegs)
87358f0484fSRodney W. Grimes {
8748fb3f3f6SDavid E. O'Brien int i;
8758fb3f3f6SDavid E. O'Brien SEGMENT store;
87658f0484fSRodney W. Grimes
87758f0484fSRodney W. Grimes int save_errno;
87858f0484fSRodney W. Grimes
87958f0484fSRodney W. Grimes if ((hashp->dir =
8801b81d865SPedro F. Giffuni calloc(hashp->DSIZE, sizeof(SEGMENT *))) == NULL) {
88158f0484fSRodney W. Grimes save_errno = errno;
88258f0484fSRodney W. Grimes (void)hdestroy(hashp);
88358f0484fSRodney W. Grimes errno = save_errno;
88458f0484fSRodney W. Grimes return (-1);
88558f0484fSRodney W. Grimes }
8866c90d46eSXin LI hashp->nsegs = nsegs;
8876c90d46eSXin LI if (nsegs == 0)
8886c90d46eSXin LI return (0);
88958f0484fSRodney W. Grimes /* Allocate segments */
8901b81d865SPedro F. Giffuni if ((store = calloc(nsegs << hashp->SSHIFT, sizeof(SEGMENT))) == NULL) {
89158f0484fSRodney W. Grimes save_errno = errno;
89258f0484fSRodney W. Grimes (void)hdestroy(hashp);
89358f0484fSRodney W. Grimes errno = save_errno;
89458f0484fSRodney W. Grimes return (-1);
89558f0484fSRodney W. Grimes }
8966c90d46eSXin LI for (i = 0; i < nsegs; i++)
89758f0484fSRodney W. Grimes hashp->dir[i] = &store[i << hashp->SSHIFT];
89858f0484fSRodney W. Grimes return (0);
89958f0484fSRodney W. Grimes }
90058f0484fSRodney W. Grimes
90158f0484fSRodney W. Grimes #if BYTE_ORDER == LITTLE_ENDIAN
90258f0484fSRodney W. Grimes /*
90358f0484fSRodney W. Grimes * Hashp->hdr needs to be byteswapped.
90458f0484fSRodney W. Grimes */
90558f0484fSRodney W. Grimes static void
swap_header_copy(HASHHDR * srcp,HASHHDR * destp)9060ac22237SXin LI swap_header_copy(HASHHDR *srcp, HASHHDR *destp)
90758f0484fSRodney W. Grimes {
90858f0484fSRodney W. Grimes int i;
90958f0484fSRodney W. Grimes
91058f0484fSRodney W. Grimes P_32_COPY(srcp->magic, destp->magic);
91158f0484fSRodney W. Grimes P_32_COPY(srcp->version, destp->version);
91258f0484fSRodney W. Grimes P_32_COPY(srcp->lorder, destp->lorder);
91358f0484fSRodney W. Grimes P_32_COPY(srcp->bsize, destp->bsize);
91458f0484fSRodney W. Grimes P_32_COPY(srcp->bshift, destp->bshift);
91558f0484fSRodney W. Grimes P_32_COPY(srcp->dsize, destp->dsize);
91658f0484fSRodney W. Grimes P_32_COPY(srcp->ssize, destp->ssize);
91758f0484fSRodney W. Grimes P_32_COPY(srcp->sshift, destp->sshift);
91858f0484fSRodney W. Grimes P_32_COPY(srcp->ovfl_point, destp->ovfl_point);
91958f0484fSRodney W. Grimes P_32_COPY(srcp->last_freed, destp->last_freed);
92058f0484fSRodney W. Grimes P_32_COPY(srcp->max_bucket, destp->max_bucket);
92158f0484fSRodney W. Grimes P_32_COPY(srcp->high_mask, destp->high_mask);
92258f0484fSRodney W. Grimes P_32_COPY(srcp->low_mask, destp->low_mask);
92358f0484fSRodney W. Grimes P_32_COPY(srcp->ffactor, destp->ffactor);
92458f0484fSRodney W. Grimes P_32_COPY(srcp->nkeys, destp->nkeys);
92558f0484fSRodney W. Grimes P_32_COPY(srcp->hdrpages, destp->hdrpages);
92658f0484fSRodney W. Grimes P_32_COPY(srcp->h_charkey, destp->h_charkey);
92758f0484fSRodney W. Grimes for (i = 0; i < NCACHED; i++) {
92858f0484fSRodney W. Grimes P_32_COPY(srcp->spares[i], destp->spares[i]);
92958f0484fSRodney W. Grimes P_16_COPY(srcp->bitmaps[i], destp->bitmaps[i]);
93058f0484fSRodney W. Grimes }
93158f0484fSRodney W. Grimes }
93258f0484fSRodney W. Grimes
93358f0484fSRodney W. Grimes static void
swap_header(HTAB * hashp)9340ac22237SXin LI swap_header(HTAB *hashp)
93558f0484fSRodney W. Grimes {
93658f0484fSRodney W. Grimes HASHHDR *hdrp;
93758f0484fSRodney W. Grimes int i;
93858f0484fSRodney W. Grimes
93958f0484fSRodney W. Grimes hdrp = &hashp->hdr;
94058f0484fSRodney W. Grimes
94158f0484fSRodney W. Grimes M_32_SWAP(hdrp->magic);
94258f0484fSRodney W. Grimes M_32_SWAP(hdrp->version);
94358f0484fSRodney W. Grimes M_32_SWAP(hdrp->lorder);
94458f0484fSRodney W. Grimes M_32_SWAP(hdrp->bsize);
94558f0484fSRodney W. Grimes M_32_SWAP(hdrp->bshift);
94658f0484fSRodney W. Grimes M_32_SWAP(hdrp->dsize);
94758f0484fSRodney W. Grimes M_32_SWAP(hdrp->ssize);
94858f0484fSRodney W. Grimes M_32_SWAP(hdrp->sshift);
94958f0484fSRodney W. Grimes M_32_SWAP(hdrp->ovfl_point);
95058f0484fSRodney W. Grimes M_32_SWAP(hdrp->last_freed);
95158f0484fSRodney W. Grimes M_32_SWAP(hdrp->max_bucket);
95258f0484fSRodney W. Grimes M_32_SWAP(hdrp->high_mask);
95358f0484fSRodney W. Grimes M_32_SWAP(hdrp->low_mask);
95458f0484fSRodney W. Grimes M_32_SWAP(hdrp->ffactor);
95558f0484fSRodney W. Grimes M_32_SWAP(hdrp->nkeys);
95658f0484fSRodney W. Grimes M_32_SWAP(hdrp->hdrpages);
95758f0484fSRodney W. Grimes M_32_SWAP(hdrp->h_charkey);
95858f0484fSRodney W. Grimes for (i = 0; i < NCACHED; i++) {
95958f0484fSRodney W. Grimes M_32_SWAP(hdrp->spares[i]);
96058f0484fSRodney W. Grimes M_16_SWAP(hdrp->bitmaps[i]);
96158f0484fSRodney W. Grimes }
96258f0484fSRodney W. Grimes }
96358f0484fSRodney W. Grimes #endif
964