|
Packit |
fd8b60 |
/*-
|
|
Packit |
fd8b60 |
* Copyright (c) 1990, 1993, 1994
|
|
Packit |
fd8b60 |
* The Regents of the University of California. All rights reserved.
|
|
Packit |
fd8b60 |
*
|
|
Packit |
fd8b60 |
* This code is derived from software contributed to Berkeley by
|
|
Packit |
fd8b60 |
* Margo Seltzer.
|
|
Packit |
fd8b60 |
*
|
|
Packit |
fd8b60 |
* Redistribution and use in source and binary forms, with or without
|
|
Packit |
fd8b60 |
* modification, are permitted provided that the following conditions
|
|
Packit |
fd8b60 |
* are met:
|
|
Packit |
fd8b60 |
* 1. Redistributions of source code must retain the above copyright
|
|
Packit |
fd8b60 |
* notice, this list of conditions and the following disclaimer.
|
|
Packit |
fd8b60 |
* 2. Redistributions in binary form must reproduce the above copyright
|
|
Packit |
fd8b60 |
* notice, this list of conditions and the following disclaimer in the
|
|
Packit |
fd8b60 |
* documentation and/or other materials provided with the distribution.
|
|
Packit |
fd8b60 |
* 3. All advertising materials mentioning features or use of this software
|
|
Packit |
fd8b60 |
* must display the following acknowledgement:
|
|
Packit |
fd8b60 |
* This product includes software developed by the University of
|
|
Packit |
fd8b60 |
* California, Berkeley and its contributors.
|
|
Packit |
fd8b60 |
* 4. Neither the name of the University nor the names of its contributors
|
|
Packit |
fd8b60 |
* may be used to endorse or promote products derived from this software
|
|
Packit |
fd8b60 |
* without specific prior written permission.
|
|
Packit |
fd8b60 |
*
|
|
Packit |
fd8b60 |
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
Packit |
fd8b60 |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
Packit |
fd8b60 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
Packit |
fd8b60 |
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
Packit |
fd8b60 |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
Packit |
fd8b60 |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
Packit |
fd8b60 |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
Packit |
fd8b60 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
Packit |
fd8b60 |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
Packit |
fd8b60 |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
Packit |
fd8b60 |
* SUCH DAMAGE.
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#if defined(LIBC_SCCS) && !defined(lint)
|
|
Packit |
fd8b60 |
static char sccsid[] = "@(#)hash.c 8.12 (Berkeley) 11/7/95";
|
|
Packit |
fd8b60 |
#endif /* LIBC_SCCS and not lint */
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#include <sys/param.h>
|
|
Packit |
fd8b60 |
#include <sys/stat.h>
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#include <errno.h>
|
|
Packit |
fd8b60 |
#include <fcntl.h>
|
|
Packit |
fd8b60 |
#include <stdio.h>
|
|
Packit |
fd8b60 |
#include <stdlib.h>
|
|
Packit |
fd8b60 |
#include <string.h>
|
|
Packit |
fd8b60 |
#include <unistd.h>
|
|
Packit |
fd8b60 |
#ifdef DEBUG
|
|
Packit |
fd8b60 |
#include <assert.h>
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
|
|
rpm-build |
c4c9c6 |
#include "k5-int.h"
|
|
Packit |
fd8b60 |
#include "db-int.h"
|
|
Packit |
fd8b60 |
#include "hash.h"
|
|
Packit |
fd8b60 |
#include "page.h"
|
|
Packit |
fd8b60 |
#include "extern.h"
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
static int32_t flush_meta __P((HTAB *));
|
|
Packit |
fd8b60 |
static int32_t hash_access __P((HTAB *, ACTION, const DBT *, DBT *));
|
|
Packit |
fd8b60 |
static int32_t hash_close __P((DB *));
|
|
Packit |
fd8b60 |
static int32_t hash_delete __P((const DB *, const DBT *, u_int32_t));
|
|
Packit |
fd8b60 |
static int32_t hash_fd __P((const DB *));
|
|
Packit |
fd8b60 |
static int32_t hash_get __P((const DB *, const DBT *, DBT *, u_int32_t));
|
|
Packit |
fd8b60 |
static int32_t hash_put __P((const DB *, DBT *, const DBT *, u_int32_t));
|
|
Packit |
fd8b60 |
static int32_t hash_seq __P((const DB *, DBT *, DBT *, u_int32_t));
|
|
Packit |
fd8b60 |
static int32_t hash_sync __P((const DB *, u_int32_t));
|
|
Packit |
fd8b60 |
static int32_t hdestroy __P((HTAB *));
|
|
Packit |
fd8b60 |
static int32_t cursor_get __P((const DB *, CURSOR *, DBT *, DBT *, \
|
|
Packit |
fd8b60 |
u_int32_t));
|
|
Packit |
fd8b60 |
static int32_t cursor_delete __P((const DB *, CURSOR *, u_int32_t));
|
|
Packit |
fd8b60 |
static HTAB *init_hash __P((HTAB *, const char *, const HASHINFO *));
|
|
Packit |
fd8b60 |
static int32_t init_htab __P((HTAB *, int32_t));
|
|
Packit |
fd8b60 |
#if DB_BYTE_ORDER == DB_LITTLE_ENDIAN
|
|
Packit |
fd8b60 |
static void swap_header __P((HTAB *));
|
|
Packit |
fd8b60 |
static void swap_header_copy __P((HASHHDR *, HASHHDR *));
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
static u_int32_t hget_header __P((HTAB *, u_int32_t));
|
|
Packit |
fd8b60 |
static void hput_header __P((HTAB *));
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#define RETURN_ERROR(ERR, LOC) { save_errno = ERR; goto LOC; }
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Return values */
|
|
Packit |
fd8b60 |
#define SUCCESS (0)
|
|
Packit |
fd8b60 |
#define ERROR (-1)
|
|
Packit |
fd8b60 |
#define ABNORMAL (1)
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#ifdef HASH_STATISTICS
|
|
Packit |
fd8b60 |
u_int32_t hash_accesses, hash_collisions, hash_expansions, hash_overflows,
|
|
Packit |
fd8b60 |
hash_bigpages;
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/************************** INTERFACE ROUTINES ***************************/
|
|
Packit |
fd8b60 |
/* OPEN/CLOSE */
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
extern DB *
|
|
Packit |
fd8b60 |
__kdb2_hash_open(file, flags, mode, info, dflags)
|
|
Packit |
fd8b60 |
const char *file;
|
|
Packit |
fd8b60 |
int flags, mode, dflags;
|
|
Packit |
fd8b60 |
const HASHINFO *info; /* Special directives for create */
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
struct stat statbuf;
|
|
Packit |
fd8b60 |
DB *dbp;
|
|
Packit |
fd8b60 |
DBT mpool_key;
|
|
Packit |
fd8b60 |
HTAB *hashp;
|
|
Packit |
fd8b60 |
int32_t bpages, csize, new_table, save_errno;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (!file || (flags & O_ACCMODE) == O_WRONLY) {
|
|
Packit |
fd8b60 |
errno = EINVAL;
|
|
Packit |
fd8b60 |
return (NULL);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
if (!(hashp = (HTAB *)calloc(1, sizeof(HTAB))))
|
|
Packit |
fd8b60 |
return (NULL);
|
|
Packit |
fd8b60 |
hashp->fp = -1;
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* Even if user wants write only, we need to be able to read
|
|
Packit |
fd8b60 |
* the actual file, so we need to open it read/write. But, the
|
|
Packit |
fd8b60 |
* field in the hashp structure needs to be accurate so that
|
|
Packit |
fd8b60 |
* we can check accesses.
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
hashp->flags = flags;
|
|
Packit |
fd8b60 |
hashp->save_file = hashp->flags & O_RDWR;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
new_table = 0;
|
|
Packit |
fd8b60 |
if (!file || (flags & O_TRUNC) ||
|
|
Packit |
fd8b60 |
(stat(file, &statbuf) && (errno == ENOENT))) {
|
|
Packit |
fd8b60 |
if (errno == ENOENT)
|
|
Packit |
fd8b60 |
errno = 0; /* In case someone looks at errno. */
|
|
Packit |
fd8b60 |
new_table = 1;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
if (file) {
|
|
rpm-build |
c4c9c6 |
if ((hashp->fp = THREEPARAMOPEN(file, flags|O_BINARY, mode)) == -1)
|
|
Packit |
fd8b60 |
RETURN_ERROR(errno, error0);
|
|
Packit |
fd8b60 |
(void)fcntl(hashp->fp, F_SETFD, 1);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Process arguments to set up hash table header. */
|
|
Packit |
fd8b60 |
if (new_table) {
|
|
Packit |
fd8b60 |
if (!(hashp = init_hash(hashp, file, info)))
|
|
Packit |
fd8b60 |
RETURN_ERROR(errno, error1);
|
|
Packit |
fd8b60 |
} else {
|
|
Packit |
fd8b60 |
/* Table already exists */
|
|
Packit |
fd8b60 |
if (info && info->hash)
|
|
Packit |
fd8b60 |
hashp->hash = info->hash;
|
|
Packit |
fd8b60 |
else
|
|
Packit |
fd8b60 |
hashp->hash = __default_hash;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* copy metadata from page into header */
|
|
Packit |
fd8b60 |
if (hget_header(hashp,
|
|
Packit |
fd8b60 |
(info && info->bsize ? info->bsize : DEF_BUCKET_SIZE)) !=
|
|
Packit |
fd8b60 |
sizeof(HASHHDR))
|
|
Packit |
fd8b60 |
RETURN_ERROR(EFTYPE, error1);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Verify file type, versions and hash function */
|
|
Packit |
fd8b60 |
if (hashp->hdr.magic != HASHMAGIC)
|
|
Packit |
fd8b60 |
RETURN_ERROR(EFTYPE, error1);
|
|
Packit |
fd8b60 |
#define OLDHASHVERSION 1
|
|
Packit |
fd8b60 |
if (hashp->hdr.version != HASHVERSION &&
|
|
Packit |
fd8b60 |
hashp->hdr.version != OLDHASHVERSION)
|
|
Packit |
fd8b60 |
RETURN_ERROR(EFTYPE, error1);
|
|
Packit |
fd8b60 |
if (hashp->hash(CHARKEY, sizeof(CHARKEY))
|
|
Packit |
fd8b60 |
!= hashp->hdr.h_charkey)
|
|
Packit |
fd8b60 |
RETURN_ERROR(EFTYPE, error1);
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* Figure out how many segments we need. Max_Bucket is the
|
|
Packit |
fd8b60 |
* maximum bucket number, so the number of buckets is
|
|
Packit |
fd8b60 |
* max_bucket + 1.
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Read in bitmaps */
|
|
Packit |
fd8b60 |
bpages = (hashp->hdr.spares[hashp->hdr.ovfl_point] +
|
|
Packit |
fd8b60 |
(hashp->hdr.bsize << BYTE_SHIFT) - 1) >>
|
|
Packit |
fd8b60 |
(hashp->hdr.bshift + BYTE_SHIFT);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
hashp->nmaps = bpages;
|
|
Packit |
fd8b60 |
(void)memset(&hashp->mapp[0], 0, bpages * sizeof(u_int32_t *));
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* start up mpool */
|
|
Packit |
fd8b60 |
mpool_key.data = (u_int8_t *)file;
|
|
Packit |
fd8b60 |
mpool_key.size = strlen(file);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (info && info->cachesize)
|
|
Packit |
fd8b60 |
csize = info->cachesize / hashp->hdr.bsize;
|
|
Packit |
fd8b60 |
else
|
|
Packit |
fd8b60 |
csize = DEF_CACHESIZE / hashp->hdr.bsize;
|
|
Packit |
fd8b60 |
hashp->mp = mpool_open(&mpool_key, hashp->fp, hashp->hdr.bsize, csize);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (!hashp->mp)
|
|
Packit |
fd8b60 |
RETURN_ERROR(errno, error1);
|
|
Packit |
fd8b60 |
mpool_filter(hashp->mp, __pgin_routine, __pgout_routine, hashp);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* For a new table, set up the bitmaps.
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
if (new_table &&
|
|
Packit |
fd8b60 |
init_htab(hashp, info && info->nelem ? info->nelem : 1))
|
|
Packit |
fd8b60 |
goto error2;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* initialize the cursor queue */
|
|
Packit |
fd8b60 |
TAILQ_INIT(&hashp->curs_queue);
|
|
Packit |
fd8b60 |
hashp->seq_cursor = NULL;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* get a chunk of memory for our split buffer */
|
|
Packit |
fd8b60 |
hashp->split_buf = (PAGE16 *)malloc(hashp->hdr.bsize);
|
|
Packit |
fd8b60 |
if (!hashp->split_buf)
|
|
Packit |
fd8b60 |
goto error2;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
hashp->new_file = new_table;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (!(dbp = (DB *)malloc(sizeof(DB))))
|
|
Packit |
fd8b60 |
goto error2;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
dbp->internal = hashp;
|
|
Packit |
fd8b60 |
dbp->close = hash_close;
|
|
Packit |
fd8b60 |
dbp->del = hash_delete;
|
|
Packit |
fd8b60 |
dbp->fd = hash_fd;
|
|
Packit |
fd8b60 |
dbp->get = hash_get;
|
|
Packit |
fd8b60 |
dbp->put = hash_put;
|
|
Packit |
fd8b60 |
dbp->seq = hash_seq;
|
|
Packit |
fd8b60 |
dbp->sync = hash_sync;
|
|
Packit |
fd8b60 |
dbp->type = DB_HASH;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#ifdef DEBUG
|
|
Packit |
fd8b60 |
(void)fprintf(stderr,
|
|
Packit |
fd8b60 |
"%s\n%s%lx\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",
|
|
Packit |
fd8b60 |
"init_htab:",
|
|
Packit |
fd8b60 |
"TABLE POINTER ", (void *)hashp,
|
|
Packit |
fd8b60 |
"BUCKET SIZE ", hashp->hdr.bsize,
|
|
Packit |
fd8b60 |
"BUCKET SHIFT ", hashp->hdr.bshift,
|
|
Packit |
fd8b60 |
"FILL FACTOR ", hashp->hdr.ffactor,
|
|
Packit |
fd8b60 |
"MAX BUCKET ", hashp->hdr.max_bucket,
|
|
Packit |
fd8b60 |
"OVFL POINT ", hashp->hdr.ovfl_point,
|
|
Packit |
fd8b60 |
"LAST FREED ", hashp->hdr.last_freed,
|
|
Packit |
fd8b60 |
"HIGH MASK ", hashp->hdr.high_mask,
|
|
Packit |
fd8b60 |
"LOW MASK ", hashp->hdr.low_mask,
|
|
Packit |
fd8b60 |
"NKEYS ", hashp->hdr.nkeys);
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
#ifdef HASH_STATISTICS
|
|
Packit |
fd8b60 |
hash_overflows = hash_accesses = hash_collisions = hash_expansions = 0;
|
|
Packit |
fd8b60 |
hash_bigpages = 0;
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
return (dbp);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
error2:
|
|
Packit |
fd8b60 |
save_errno = errno;
|
|
Packit |
fd8b60 |
hdestroy(hashp);
|
|
Packit |
fd8b60 |
errno = save_errno;
|
|
Packit |
fd8b60 |
return (NULL);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
error1:
|
|
Packit |
fd8b60 |
if (hashp != NULL)
|
|
Packit |
fd8b60 |
(void)close(hashp->fp);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
error0:
|
|
Packit |
fd8b60 |
free(hashp);
|
|
Packit |
fd8b60 |
errno = save_errno;
|
|
Packit |
fd8b60 |
return (NULL);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
static int32_t
|
|
Packit |
fd8b60 |
hash_close(dbp)
|
|
Packit |
fd8b60 |
DB *dbp;
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
HTAB *hashp;
|
|
Packit |
fd8b60 |
int32_t retval;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (!dbp)
|
|
Packit |
fd8b60 |
return (ERROR);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
hashp = (HTAB *)dbp->internal;
|
|
Packit |
fd8b60 |
retval = hdestroy(hashp);
|
|
Packit |
fd8b60 |
free(dbp);
|
|
Packit |
fd8b60 |
return (retval);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
static int32_t
|
|
Packit |
fd8b60 |
hash_fd(dbp)
|
|
Packit |
fd8b60 |
const DB *dbp;
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
HTAB *hashp;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (!dbp)
|
|
Packit |
fd8b60 |
return (ERROR);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
hashp = (HTAB *)dbp->internal;
|
|
Packit |
fd8b60 |
if (hashp->fp == -1) {
|
|
Packit |
fd8b60 |
errno = ENOENT;
|
|
Packit |
fd8b60 |
return (-1);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
return (hashp->fp);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/************************** LOCAL CREATION ROUTINES **********************/
|
|
Packit |
fd8b60 |
static HTAB *
|
|
Packit |
fd8b60 |
init_hash(hashp, file, info)
|
|
Packit |
fd8b60 |
HTAB *hashp;
|
|
Packit |
fd8b60 |
const char *file;
|
|
Packit |
fd8b60 |
const HASHINFO *info;
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
struct stat statbuf;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
hashp->hdr.nkeys = 0;
|
|
Packit |
fd8b60 |
hashp->hdr.lorder = DB_BYTE_ORDER;
|
|
Packit |
fd8b60 |
hashp->hdr.bsize = DEF_BUCKET_SIZE;
|
|
Packit |
fd8b60 |
hashp->hdr.bshift = DEF_BUCKET_SHIFT;
|
|
Packit |
fd8b60 |
hashp->hdr.ffactor = DEF_FFACTOR;
|
|
Packit |
fd8b60 |
hashp->hash = __default_hash;
|
|
Packit |
fd8b60 |
memset(hashp->hdr.spares, 0, sizeof(hashp->hdr.spares));
|
|
Packit |
fd8b60 |
memset(hashp->hdr.bitmaps, 0, sizeof(hashp->hdr.bitmaps));
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Fix bucket size to be optimal for file system */
|
|
Packit |
fd8b60 |
if (file != NULL) {
|
|
Packit |
fd8b60 |
if (stat(file, &statbuf))
|
|
Packit |
fd8b60 |
return (NULL);
|
|
Packit |
fd8b60 |
hashp->hdr.bsize = statbuf.st_blksize;
|
|
Packit |
fd8b60 |
if (hashp->hdr.bsize > MAX_BSIZE)
|
|
Packit |
fd8b60 |
hashp->hdr.bsize = MAX_BSIZE;
|
|
Packit |
fd8b60 |
hashp->hdr.bshift = __log2(hashp->hdr.bsize);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
if (info) {
|
|
Packit |
fd8b60 |
if (info->bsize) {
|
|
Packit |
fd8b60 |
/* Round pagesize up to power of 2 */
|
|
Packit |
fd8b60 |
hashp->hdr.bshift = __log2(info->bsize);
|
|
Packit |
fd8b60 |
hashp->hdr.bsize = 1 << hashp->hdr.bshift;
|
|
Packit |
fd8b60 |
if (hashp->hdr.bsize > MAX_BSIZE) {
|
|
Packit |
fd8b60 |
errno = EINVAL;
|
|
Packit |
fd8b60 |
return (NULL);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
if (info->ffactor)
|
|
Packit |
fd8b60 |
hashp->hdr.ffactor = info->ffactor;
|
|
Packit |
fd8b60 |
if (info->hash)
|
|
Packit |
fd8b60 |
hashp->hash = info->hash;
|
|
Packit |
fd8b60 |
if (info->lorder) {
|
|
Packit |
fd8b60 |
if ((info->lorder != DB_BIG_ENDIAN) &&
|
|
Packit |
fd8b60 |
(info->lorder != DB_LITTLE_ENDIAN)) {
|
|
Packit |
fd8b60 |
errno = EINVAL;
|
|
Packit |
fd8b60 |
return (NULL);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
hashp->hdr.lorder = info->lorder;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
return (hashp);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* Returns 0 on No Error
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
static int32_t
|
|
Packit |
fd8b60 |
init_htab(hashp, nelem)
|
|
Packit |
fd8b60 |
HTAB *hashp;
|
|
Packit |
fd8b60 |
int32_t nelem;
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
int32_t l2, nbuckets;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* Divide number of elements by the fill factor and determine a
|
|
Packit |
fd8b60 |
* desired number of buckets. Allocate space for the next greater
|
|
Packit |
fd8b60 |
* power of two number of buckets.
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
nelem = (nelem - 1) / hashp->hdr.ffactor + 1;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
l2 = __log2(MAX(nelem, 2));
|
|
Packit |
fd8b60 |
nbuckets = 1 << l2;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
hashp->hdr.spares[l2] = l2 + 1;
|
|
Packit |
fd8b60 |
hashp->hdr.spares[l2 + 1] = l2 + 1;
|
|
Packit |
fd8b60 |
hashp->hdr.ovfl_point = l2;
|
|
Packit |
fd8b60 |
hashp->hdr.last_freed = 2;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
hashp->hdr.max_bucket = hashp->hdr.low_mask = nbuckets - 1;
|
|
Packit |
fd8b60 |
hashp->hdr.high_mask = (nbuckets << 1) - 1;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* The number of header pages is the size of the header divided by
|
|
Packit |
fd8b60 |
* the amount of freespace on header pages (the page size - the
|
|
Packit |
fd8b60 |
* size of 1 integer where the length of the header info on that
|
|
Packit |
fd8b60 |
* page is stored) plus another page if it didn't divide evenly.
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
hashp->hdr.hdrpages =
|
|
Packit |
fd8b60 |
(sizeof(HASHHDR) / (hashp->hdr.bsize - HEADER_OVERHEAD)) +
|
|
Packit |
fd8b60 |
(((sizeof(HASHHDR) % (hashp->hdr.bsize - HEADER_OVERHEAD)) == 0)
|
|
Packit |
fd8b60 |
? 0 : 1);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Create pages for these buckets */
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
for (i = 0; i <= hashp->hdr.max_bucket; i++) {
|
|
Packit |
fd8b60 |
if (__new_page(hashp, (u_int32_t)i, A_BUCKET) != 0)
|
|
Packit |
fd8b60 |
return (-1);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* First bitmap page is at: splitpoint l2 page offset 1 */
|
|
Packit |
fd8b60 |
if (__ibitmap(hashp, OADDR_OF(l2, 1), l2 + 1, 0))
|
|
Packit |
fd8b60 |
return (-1);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
return (0);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* Functions to get/put hash header. We access the file directly.
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
static u_int32_t
|
|
Packit |
fd8b60 |
hget_header(hashp, page_size)
|
|
Packit |
fd8b60 |
HTAB *hashp;
|
|
Packit |
fd8b60 |
u_int32_t page_size;
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
u_int32_t num_copied;
|
|
Packit |
fd8b60 |
u_int8_t *hdr_dest;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
num_copied = 0;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
hdr_dest = (u_int8_t *)&hashp->hdr;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* XXX
|
|
Packit |
fd8b60 |
* This should not be printing to stderr on a "normal" error case.
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
lseek(hashp->fp, 0, SEEK_SET);
|
|
Packit |
fd8b60 |
num_copied = read(hashp->fp, hdr_dest, sizeof(HASHHDR));
|
|
Packit |
fd8b60 |
if (num_copied != sizeof(HASHHDR)) {
|
|
Packit |
fd8b60 |
fprintf(stderr, "hash: could not retrieve header");
|
|
Packit |
fd8b60 |
return (0);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
#if DB_BYTE_ORDER == DB_LITTLE_ENDIAN
|
|
Packit |
fd8b60 |
swap_header(hashp);
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
return (num_copied);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
static void
|
|
Packit |
fd8b60 |
hput_header(hashp)
|
|
Packit |
fd8b60 |
HTAB *hashp;
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
HASHHDR *whdrp;
|
|
Packit |
fd8b60 |
#if DB_BYTE_ORDER == DB_LITTLE_ENDIAN
|
|
Packit |
fd8b60 |
HASHHDR whdr;
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
u_int32_t num_copied;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
num_copied = 0;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
whdrp = &hashp->hdr;
|
|
Packit |
fd8b60 |
#if DB_BYTE_ORDER == DB_LITTLE_ENDIAN
|
|
Packit |
fd8b60 |
whdrp = &whdr;
|
|
Packit |
fd8b60 |
swap_header_copy(&hashp->hdr, whdrp);
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
lseek(hashp->fp, 0, SEEK_SET);
|
|
Packit |
fd8b60 |
num_copied = write(hashp->fp, whdrp, sizeof(HASHHDR));
|
|
Packit |
fd8b60 |
if (num_copied != sizeof(HASHHDR))
|
|
Packit |
fd8b60 |
(void)fprintf(stderr, "hash: could not write hash header");
|
|
Packit |
fd8b60 |
return;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/********************** DESTROY/CLOSE ROUTINES ************************/
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* Flushes any changes to the file if necessary and destroys the hashp
|
|
Packit |
fd8b60 |
* structure, freeing all allocated space.
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
static int32_t
|
|
Packit |
fd8b60 |
hdestroy(hashp)
|
|
Packit |
fd8b60 |
HTAB *hashp;
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
int32_t save_errno;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
save_errno = 0;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#ifdef HASH_STATISTICS
|
|
Packit |
fd8b60 |
{ int i;
|
|
Packit |
fd8b60 |
(void)fprintf(stderr, "hdestroy: accesses %ld collisions %ld\n",
|
|
Packit |
fd8b60 |
hash_accesses, hash_collisions);
|
|
Packit |
fd8b60 |
(void)fprintf(stderr,
|
|
Packit |
fd8b60 |
"hdestroy: expansions %ld\n", hash_expansions);
|
|
Packit |
fd8b60 |
(void)fprintf(stderr,
|
|
Packit |
fd8b60 |
"hdestroy: overflows %ld\n", hash_overflows);
|
|
Packit |
fd8b60 |
(void)fprintf(stderr,
|
|
Packit |
fd8b60 |
"hdestroy: big key/data pages %ld\n", hash_bigpages);
|
|
Packit |
fd8b60 |
(void)fprintf(stderr,
|
|
Packit |
fd8b60 |
"keys %ld maxp %d\n", hashp->hdr.nkeys, hashp->hdr.max_bucket);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
for (i = 0; i < NCACHED; i++)
|
|
Packit |
fd8b60 |
(void)fprintf(stderr,
|
|
Packit |
fd8b60 |
"spares[%d] = %d\n", i, hashp->hdr.spares[i]);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (flush_meta(hashp) && !save_errno)
|
|
Packit |
fd8b60 |
save_errno = errno;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Free the split page */
|
|
Packit |
fd8b60 |
if (hashp->split_buf)
|
|
Packit |
fd8b60 |
free(hashp->split_buf);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Free the big key and big data returns */
|
|
Packit |
fd8b60 |
if (hashp->bigkey_buf)
|
|
Packit |
fd8b60 |
free(hashp->bigkey_buf);
|
|
Packit |
fd8b60 |
if (hashp->bigdata_buf)
|
|
Packit |
fd8b60 |
free(hashp->bigdata_buf);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* XXX This should really iterate over the cursor queue, but
|
|
Packit |
fd8b60 |
it's not clear how to do that, and the only cursor a hash
|
|
Packit |
fd8b60 |
table ever creates is the one used by hash_seq(). Passing
|
|
Packit |
fd8b60 |
NULL as the first arg is also a kludge, but I know that
|
|
Packit |
fd8b60 |
it's never used, so I do it. The intent is to plug the
|
|
Packit |
fd8b60 |
memory leak. Correctness can come later. */
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (hashp->seq_cursor)
|
|
Packit |
fd8b60 |
hashp->seq_cursor->delete(NULL, hashp->seq_cursor, 0);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* shut down mpool */
|
|
Packit |
fd8b60 |
mpool_sync(hashp->mp);
|
|
Packit |
fd8b60 |
mpool_close(hashp->mp);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (hashp->fp != -1)
|
|
Packit |
fd8b60 |
(void)close(hashp->fp);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* *** This may cause problems if hashp->fname is set in any case
|
|
Packit |
fd8b60 |
* other than the case that we are generating a temporary file name.
|
|
Packit |
fd8b60 |
* Note that the new version of mpool should support temporary
|
|
Packit |
fd8b60 |
* files within mpool itself.
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
if (hashp->fname && !hashp->save_file) {
|
|
Packit |
fd8b60 |
#ifdef DEBUG
|
|
Packit |
fd8b60 |
fprintf(stderr, "Unlinking file %s.\n", hashp->fname);
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
/* we need to chmod the file to allow it to be deleted... */
|
|
Packit |
fd8b60 |
chmod(hashp->fname, 0700);
|
|
Packit |
fd8b60 |
unlink(hashp->fname);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
free(hashp);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (save_errno) {
|
|
Packit |
fd8b60 |
errno = save_errno;
|
|
Packit |
fd8b60 |
return (ERROR);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
return (SUCCESS);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* Write modified pages to disk
|
|
Packit |
fd8b60 |
*
|
|
Packit |
fd8b60 |
* Returns:
|
|
Packit |
fd8b60 |
* 0 == OK
|
|
Packit |
fd8b60 |
* -1 ERROR
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
static int32_t
|
|
Packit |
fd8b60 |
hash_sync(dbp, flags)
|
|
Packit |
fd8b60 |
const DB *dbp;
|
|
Packit |
fd8b60 |
u_int32_t flags;
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
HTAB *hashp;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
hashp = (HTAB *)dbp->internal;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* XXX
|
|
Packit |
fd8b60 |
* Check success/failure conditions.
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
return (flush_meta(hashp) || mpool_sync(hashp->mp));
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* Returns:
|
|
Packit |
fd8b60 |
* 0 == OK
|
|
Packit |
fd8b60 |
* -1 indicates that errno should be set
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
static int32_t
|
|
Packit |
fd8b60 |
flush_meta(hashp)
|
|
Packit |
fd8b60 |
HTAB *hashp;
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
int32_t i;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (!hashp->save_file)
|
|
Packit |
fd8b60 |
return (0);
|
|
Packit |
fd8b60 |
hashp->hdr.magic = HASHMAGIC;
|
|
Packit |
fd8b60 |
hashp->hdr.version = HASHVERSION;
|
|
Packit |
fd8b60 |
hashp->hdr.h_charkey = hashp->hash(CHARKEY, sizeof(CHARKEY));
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* write out metadata */
|
|
Packit |
fd8b60 |
hput_header(hashp);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
for (i = 0; i < NCACHED; i++)
|
|
Packit |
fd8b60 |
if (hashp->mapp[i]) {
|
|
Packit |
fd8b60 |
if (__put_page(hashp,
|
|
Packit |
fd8b60 |
(PAGE16 *)hashp->mapp[i], A_BITMAP, 1))
|
|
Packit |
fd8b60 |
return (-1);
|
|
Packit |
fd8b60 |
hashp->mapp[i] = NULL;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
return (0);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/*******************************SEARCH ROUTINES *****************************/
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* All the access routines return
|
|
Packit |
fd8b60 |
*
|
|
Packit |
fd8b60 |
* Returns:
|
|
Packit |
fd8b60 |
* 0 on SUCCESS
|
|
Packit |
fd8b60 |
* 1 to indicate an external ERROR (i.e. key not found, etc)
|
|
Packit |
fd8b60 |
* -1 to indicate an internal ERROR (i.e. out of memory, etc)
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* *** make sure this is true! */
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
static int32_t
|
|
Packit |
fd8b60 |
hash_get(dbp, key, data, flag)
|
|
Packit |
fd8b60 |
const DB *dbp;
|
|
Packit |
fd8b60 |
const DBT *key;
|
|
Packit |
fd8b60 |
DBT *data;
|
|
Packit |
fd8b60 |
u_int32_t flag;
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
HTAB *hashp;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
hashp = (HTAB *)dbp->internal;
|
|
Packit |
fd8b60 |
if (flag) {
|
|
Packit |
fd8b60 |
hashp->local_errno = errno = EINVAL;
|
|
Packit |
fd8b60 |
return (ERROR);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
return (hash_access(hashp, HASH_GET, key, data));
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
static int32_t
|
|
Packit |
fd8b60 |
hash_put(dbp, key, data, flag)
|
|
Packit |
fd8b60 |
const DB *dbp;
|
|
Packit |
fd8b60 |
DBT *key;
|
|
Packit |
fd8b60 |
const DBT *data;
|
|
Packit |
fd8b60 |
u_int32_t flag;
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
HTAB *hashp;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
hashp = (HTAB *)dbp->internal;
|
|
Packit |
fd8b60 |
if (flag && flag != R_NOOVERWRITE) {
|
|
Packit |
fd8b60 |
hashp->local_errno = errno = EINVAL;
|
|
Packit |
fd8b60 |
return (ERROR);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
if ((hashp->flags & O_ACCMODE) == O_RDONLY) {
|
|
Packit |
fd8b60 |
hashp->local_errno = errno = EPERM;
|
|
Packit |
fd8b60 |
return (ERROR);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
return (hash_access(hashp, flag == R_NOOVERWRITE ?
|
|
Packit |
fd8b60 |
HASH_PUTNEW : HASH_PUT, key, (DBT *)data));
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
static int32_t
|
|
Packit |
fd8b60 |
hash_delete(dbp, key, flag)
|
|
Packit |
fd8b60 |
const DB *dbp;
|
|
Packit |
fd8b60 |
const DBT *key;
|
|
Packit |
fd8b60 |
u_int32_t flag; /* Ignored */
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
HTAB *hashp;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
hashp = (HTAB *)dbp->internal;
|
|
Packit |
fd8b60 |
if (flag) {
|
|
Packit |
fd8b60 |
hashp->local_errno = errno = EINVAL;
|
|
Packit |
fd8b60 |
return (ERROR);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
if ((hashp->flags & O_ACCMODE) == O_RDONLY) {
|
|
Packit |
fd8b60 |
hashp->local_errno = errno = EPERM;
|
|
Packit |
fd8b60 |
return (ERROR);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
return (hash_access(hashp, HASH_DELETE, key, NULL));
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* Assume that hashp has been set in wrapper routine.
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
static int32_t
|
|
Packit |
fd8b60 |
hash_access(hashp, action, key, val)
|
|
Packit |
fd8b60 |
HTAB *hashp;
|
|
Packit |
fd8b60 |
ACTION action;
|
|
Packit |
fd8b60 |
const DBT *key;
|
|
Packit |
fd8b60 |
DBT *val;
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
DBT page_key, page_val;
|
|
Packit |
fd8b60 |
CURSOR cursor;
|
|
Packit |
fd8b60 |
ITEM_INFO item_info;
|
|
Packit |
fd8b60 |
u_int32_t bucket;
|
|
Packit |
fd8b60 |
u_int32_t num_items;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#ifdef HASH_STATISTICS
|
|
Packit |
fd8b60 |
hash_accesses++;
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
num_items = 0;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* Set up item_info so that we're looking for space to add an item
|
|
Packit |
fd8b60 |
* as we cycle through the pages looking for the key.
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
if (action == HASH_PUT || action == HASH_PUTNEW) {
|
|
Packit |
fd8b60 |
if (ISBIG(key->size + val->size, hashp))
|
|
Packit |
fd8b60 |
item_info.seek_size = PAIR_OVERHEAD;
|
|
Packit |
fd8b60 |
else
|
|
Packit |
fd8b60 |
item_info.seek_size = key->size + val->size;
|
|
Packit |
fd8b60 |
} else
|
|
Packit |
fd8b60 |
item_info.seek_size = 0;
|
|
Packit |
fd8b60 |
item_info.seek_found_page = 0;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
bucket = __call_hash(hashp, (int8_t *)key->data, key->size);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
cursor.pagep = NULL;
|
|
Packit |
fd8b60 |
__get_item_reset(hashp, &cursor);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
cursor.bucket = bucket;
|
|
Packit |
fd8b60 |
while (1) {
|
|
Packit |
fd8b60 |
__get_item_next(hashp, &cursor, &page_key, &page_val, &item_info);
|
|
Packit |
fd8b60 |
if (item_info.status == ITEM_ERROR)
|
|
Packit |
fd8b60 |
return (ABNORMAL);
|
|
Packit |
fd8b60 |
if (item_info.status == ITEM_NO_MORE)
|
|
Packit |
fd8b60 |
break;
|
|
Packit |
fd8b60 |
num_items++;
|
|
Packit |
fd8b60 |
if (item_info.key_off == BIGPAIR) {
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* !!!
|
|
Packit |
fd8b60 |
* 0 is a valid index.
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
if (__find_bigpair(hashp, &cursor, (int8_t *)key->data,
|
|
Packit |
fd8b60 |
key->size) > 0)
|
|
Packit |
fd8b60 |
goto found;
|
|
Packit |
fd8b60 |
} else if (key->size == page_key.size &&
|
|
Packit |
fd8b60 |
!memcmp(key->data, page_key.data, key->size))
|
|
Packit |
fd8b60 |
goto found;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
#ifdef HASH_STATISTICS
|
|
Packit |
fd8b60 |
hash_collisions++;
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
__get_item_done(hashp, &cursor);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* At this point, item_info will list either the last page in
|
|
Packit |
fd8b60 |
* the chain, or the last page in the chain plus a pgno for where
|
|
Packit |
fd8b60 |
* to find the first page in the chain with space for the
|
|
Packit |
fd8b60 |
* item we wish to add.
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Not found */
|
|
Packit |
fd8b60 |
switch (action) {
|
|
Packit |
fd8b60 |
case HASH_PUT:
|
|
Packit |
fd8b60 |
case HASH_PUTNEW:
|
|
Packit |
fd8b60 |
if (__addel(hashp, &item_info, key, val, num_items, 0))
|
|
Packit |
fd8b60 |
return (ERROR);
|
|
Packit |
fd8b60 |
break;
|
|
Packit |
fd8b60 |
case HASH_GET:
|
|
Packit |
fd8b60 |
case HASH_DELETE:
|
|
Packit |
fd8b60 |
default:
|
|
Packit |
fd8b60 |
return (ABNORMAL);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (item_info.caused_expand)
|
|
Packit |
fd8b60 |
__expand_table(hashp);
|
|
Packit |
fd8b60 |
return (SUCCESS);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
found: __get_item_done(hashp, &cursor);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
switch (action) {
|
|
Packit |
fd8b60 |
case HASH_PUTNEW:
|
|
Packit |
fd8b60 |
/* mpool_put(hashp->mp, pagep, 0); */
|
|
Packit |
fd8b60 |
return (ABNORMAL);
|
|
Packit |
fd8b60 |
case HASH_GET:
|
|
Packit |
fd8b60 |
if (item_info.key_off == BIGPAIR) {
|
|
Packit |
fd8b60 |
if (__big_return(hashp, &item_info, val, 0))
|
|
Packit |
fd8b60 |
return (ERROR);
|
|
Packit |
fd8b60 |
} else {
|
|
Packit |
fd8b60 |
val->data = page_val.data;
|
|
Packit |
fd8b60 |
val->size = page_val.size;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
/* *** data may not be available! */
|
|
Packit |
fd8b60 |
break;
|
|
Packit |
fd8b60 |
case HASH_PUT:
|
|
Packit |
fd8b60 |
if (__delpair(hashp, &cursor, &item_info) ||
|
|
Packit |
fd8b60 |
__addel(hashp, &item_info, key, val, UNKNOWN, 0))
|
|
Packit |
fd8b60 |
return (ERROR);
|
|
Packit |
fd8b60 |
__get_item_done(hashp, &cursor);
|
|
Packit |
fd8b60 |
if (item_info.caused_expand)
|
|
Packit |
fd8b60 |
__expand_table(hashp);
|
|
Packit |
fd8b60 |
break;
|
|
Packit |
fd8b60 |
case HASH_DELETE:
|
|
Packit |
fd8b60 |
if (__delpair(hashp, &cursor, &item_info))
|
|
Packit |
fd8b60 |
return (ERROR);
|
|
Packit |
fd8b60 |
break;
|
|
Packit |
fd8b60 |
default:
|
|
Packit |
fd8b60 |
abort();
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
return (SUCCESS);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* ****************** CURSORS ********************************** */
|
|
Packit |
fd8b60 |
CURSOR *
|
|
Packit |
fd8b60 |
__cursor_creat(dbp)
|
|
Packit |
fd8b60 |
const DB *dbp;
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
CURSOR *new_curs;
|
|
Packit |
fd8b60 |
HTAB *hashp;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
new_curs = (CURSOR *)malloc(sizeof(struct cursor_t));
|
|
Packit |
fd8b60 |
if (!new_curs)
|
|
Packit |
fd8b60 |
return NULL;
|
|
Packit |
fd8b60 |
new_curs->internal =
|
|
Packit |
fd8b60 |
(struct item_info *)malloc(sizeof(struct item_info));
|
|
Packit |
fd8b60 |
if (!new_curs->internal) {
|
|
Packit |
fd8b60 |
free(new_curs);
|
|
Packit |
fd8b60 |
return NULL;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
new_curs->get = cursor_get;
|
|
Packit |
fd8b60 |
new_curs->delete = cursor_delete;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
new_curs->bucket = 0;
|
|
Packit |
fd8b60 |
new_curs->pgno = INVALID_PGNO;
|
|
Packit |
fd8b60 |
new_curs->ndx = 0;
|
|
Packit |
fd8b60 |
new_curs->pgndx = 0;
|
|
Packit |
fd8b60 |
new_curs->pagep = NULL;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* place onto queue of cursors */
|
|
Packit |
fd8b60 |
hashp = (HTAB *)dbp->internal;
|
|
Packit |
fd8b60 |
TAILQ_INSERT_TAIL(&hashp->curs_queue, new_curs, queue);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
return new_curs;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
static int32_t
|
|
Packit |
fd8b60 |
cursor_get(dbp, cursorp, key, val, flags)
|
|
Packit |
fd8b60 |
const DB *dbp;
|
|
Packit |
fd8b60 |
CURSOR *cursorp;
|
|
Packit |
fd8b60 |
DBT *key, *val;
|
|
Packit |
fd8b60 |
u_int32_t flags;
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
HTAB *hashp;
|
|
Packit |
fd8b60 |
ITEM_INFO item_info;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
hashp = (HTAB *)dbp->internal;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (flags && flags != R_FIRST && flags != R_NEXT) {
|
|
Packit |
fd8b60 |
hashp->local_errno = errno = EINVAL;
|
|
Packit |
fd8b60 |
return (ERROR);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
#ifdef HASH_STATISTICS
|
|
Packit |
fd8b60 |
hash_accesses++;
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
item_info.seek_size = 0;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
if (flags == R_FIRST)
|
|
Packit |
fd8b60 |
__get_item_first(hashp, cursorp, key, val, &item_info);
|
|
Packit |
fd8b60 |
else
|
|
Packit |
fd8b60 |
__get_item_next(hashp, cursorp, key, val, &item_info);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* This needs to be changed around. As is, get_item_next advances
|
|
Packit |
fd8b60 |
* the pointers on the page but this function actually advances
|
|
Packit |
fd8b60 |
* bucket pointers. This works, since the only other place we
|
|
Packit |
fd8b60 |
* use get_item_next is in hash_access which only deals with one
|
|
Packit |
fd8b60 |
* bucket at a time. However, there is the problem that certain other
|
|
Packit |
fd8b60 |
* functions (such as find_bigpair and delpair) depend on the
|
|
Packit |
fd8b60 |
* pgndx member of the cursor. Right now, they are using pngdx - 1
|
|
Packit |
fd8b60 |
* since indices refer to the __next__ item that is to be fetched
|
|
Packit |
fd8b60 |
* from the page. This is ugly, as you may have noticed, whoever
|
|
Packit |
fd8b60 |
* you are. The best solution would be to depend on item_infos to
|
|
Packit |
fd8b60 |
* deal with _current_ information, and have the cursors only
|
|
Packit |
fd8b60 |
* deal with _next_ information. In that scheme, get_item_next
|
|
Packit |
fd8b60 |
* would also advance buckets. Version 3...
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* Must always enter this loop to do error handling and
|
|
Packit |
fd8b60 |
* check for big key/data pair.
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
while (1) {
|
|
Packit |
fd8b60 |
if (item_info.status == ITEM_OK) {
|
|
Packit |
fd8b60 |
if (item_info.key_off == BIGPAIR &&
|
|
Packit |
fd8b60 |
__big_keydata(hashp, cursorp->pagep, key, val,
|
|
Packit |
fd8b60 |
item_info.pgndx))
|
|
Packit |
fd8b60 |
return (ABNORMAL);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
break;
|
|
Packit |
fd8b60 |
} else if (item_info.status != ITEM_NO_MORE)
|
|
Packit |
fd8b60 |
return (ABNORMAL);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
__put_page(hashp, cursorp->pagep, A_RAW, 0);
|
|
Packit |
fd8b60 |
cursorp->ndx = cursorp->pgndx = 0;
|
|
Packit |
fd8b60 |
cursorp->bucket++;
|
|
Packit |
fd8b60 |
cursorp->pgno = INVALID_PGNO;
|
|
Packit |
fd8b60 |
cursorp->pagep = NULL;
|
|
Packit |
fd8b60 |
if (cursorp->bucket > hashp->hdr.max_bucket)
|
|
Packit |
fd8b60 |
return (ABNORMAL);
|
|
Packit |
fd8b60 |
__get_item_next(hashp, cursorp, key, val, &item_info);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
__get_item_done(hashp, cursorp);
|
|
Packit |
fd8b60 |
return (0);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
static int32_t
|
|
Packit |
fd8b60 |
cursor_delete(dbp, cursor, flags)
|
|
Packit |
fd8b60 |
const DB *dbp;
|
|
Packit |
fd8b60 |
CURSOR *cursor;
|
|
Packit |
fd8b60 |
u_int32_t flags;
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
/* XXX this is empirically determined, so it might not be completely
|
|
Packit |
fd8b60 |
correct, but it seems to work. At the very least it fixes
|
|
Packit |
fd8b60 |
a memory leak */
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
free(cursor->internal);
|
|
Packit |
fd8b60 |
free(cursor);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
return (0);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
static int32_t
|
|
Packit |
fd8b60 |
hash_seq(dbp, key, val, flag)
|
|
Packit |
fd8b60 |
const DB *dbp;
|
|
Packit |
fd8b60 |
DBT *key, *val;
|
|
Packit |
fd8b60 |
u_int32_t flag;
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
HTAB *hashp;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* Seq just uses the default cursor to go sequecing through the
|
|
Packit |
fd8b60 |
* database. Note that the default cursor is the first in the list.
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
hashp = (HTAB *)dbp->internal;
|
|
Packit |
fd8b60 |
if (!hashp->seq_cursor)
|
|
Packit |
fd8b60 |
hashp->seq_cursor = __cursor_creat(dbp);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
return (hashp->seq_cursor->get(dbp, hashp->seq_cursor, key, val, flag));
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/********************************* UTILITIES ************************/
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* Returns:
|
|
Packit |
fd8b60 |
* 0 ==> OK
|
|
Packit |
fd8b60 |
* -1 ==> Error
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
int32_t
|
|
Packit |
fd8b60 |
__expand_table(hashp)
|
|
Packit |
fd8b60 |
HTAB *hashp;
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
u_int32_t old_bucket, new_bucket;
|
|
Packit |
fd8b60 |
int32_t spare_ndx;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#ifdef HASH_STATISTICS
|
|
Packit |
fd8b60 |
hash_expansions++;
|
|
Packit |
fd8b60 |
#endif
|
|
Packit |
fd8b60 |
new_bucket = ++hashp->hdr.max_bucket;
|
|
Packit |
fd8b60 |
old_bucket = (hashp->hdr.max_bucket & hashp->hdr.low_mask);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/* Get a page for this new bucket */
|
|
Packit |
fd8b60 |
if (__new_page(hashp, new_bucket, A_BUCKET) != 0)
|
|
Packit |
fd8b60 |
return (-1);
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* If the split point is increasing (hdr.max_bucket's log base 2
|
|
Packit |
fd8b60 |
* increases), we need to copy the current contents of the spare
|
|
Packit |
fd8b60 |
* split bucket to the next bucket.
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
spare_ndx = __log2(hashp->hdr.max_bucket + 1);
|
|
Packit |
fd8b60 |
if (spare_ndx > hashp->hdr.ovfl_point) {
|
|
Packit |
fd8b60 |
hashp->hdr.spares[spare_ndx] = hashp->hdr.spares[hashp->hdr.ovfl_point];
|
|
Packit |
fd8b60 |
hashp->hdr.ovfl_point = spare_ndx;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
if (new_bucket > hashp->hdr.high_mask) {
|
|
Packit |
fd8b60 |
/* Starting a new doubling */
|
|
Packit |
fd8b60 |
hashp->hdr.low_mask = hashp->hdr.high_mask;
|
|
Packit |
fd8b60 |
hashp->hdr.high_mask = new_bucket | hashp->hdr.low_mask;
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
if (BUCKET_TO_PAGE(new_bucket) > MAX_PAGES(hashp)) {
|
|
Packit |
fd8b60 |
fprintf(stderr, "hash: Cannot allocate new bucket. Pages exhausted.\n");
|
|
Packit |
fd8b60 |
return (-1);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
/* Relocate records to the new bucket */
|
|
Packit |
fd8b60 |
return (__split_page(hashp, old_bucket, new_bucket));
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
u_int32_t
|
|
Packit |
fd8b60 |
__call_hash(hashp, k, len)
|
|
Packit |
fd8b60 |
HTAB *hashp;
|
|
Packit |
fd8b60 |
int8_t *k;
|
|
Packit |
fd8b60 |
int32_t len;
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
u_int32_t n, bucket;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
n = hashp->hash(k, len);
|
|
Packit |
fd8b60 |
bucket = n & hashp->hdr.high_mask;
|
|
Packit |
fd8b60 |
if (bucket > hashp->hdr.max_bucket)
|
|
Packit |
fd8b60 |
bucket = bucket & hashp->hdr.low_mask;
|
|
Packit |
fd8b60 |
return (bucket);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
#if DB_BYTE_ORDER == DB_LITTLE_ENDIAN
|
|
Packit |
fd8b60 |
/*
|
|
Packit |
fd8b60 |
* Hashp->hdr needs to be byteswapped.
|
|
Packit |
fd8b60 |
*/
|
|
Packit |
fd8b60 |
static void
|
|
Packit |
fd8b60 |
swap_header_copy(srcp, destp)
|
|
Packit |
fd8b60 |
HASHHDR *srcp, *destp;
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
int32_t i;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
P_32_COPY(srcp->magic, destp->magic);
|
|
Packit |
fd8b60 |
P_32_COPY(srcp->version, destp->version);
|
|
Packit |
fd8b60 |
P_32_COPY(srcp->lorder, destp->lorder);
|
|
Packit |
fd8b60 |
P_32_COPY(srcp->bsize, destp->bsize);
|
|
Packit |
fd8b60 |
P_32_COPY(srcp->bshift, destp->bshift);
|
|
Packit |
fd8b60 |
P_32_COPY(srcp->ovfl_point, destp->ovfl_point);
|
|
Packit |
fd8b60 |
P_32_COPY(srcp->last_freed, destp->last_freed);
|
|
Packit |
fd8b60 |
P_32_COPY(srcp->max_bucket, destp->max_bucket);
|
|
Packit |
fd8b60 |
P_32_COPY(srcp->high_mask, destp->high_mask);
|
|
Packit |
fd8b60 |
P_32_COPY(srcp->low_mask, destp->low_mask);
|
|
Packit |
fd8b60 |
P_32_COPY(srcp->ffactor, destp->ffactor);
|
|
Packit |
fd8b60 |
P_32_COPY(srcp->nkeys, destp->nkeys);
|
|
Packit |
fd8b60 |
P_32_COPY(srcp->hdrpages, destp->hdrpages);
|
|
Packit |
fd8b60 |
P_32_COPY(srcp->h_charkey, destp->h_charkey);
|
|
Packit |
fd8b60 |
for (i = 0; i < NCACHED; i++) {
|
|
Packit |
fd8b60 |
P_32_COPY(srcp->spares[i], destp->spares[i]);
|
|
Packit |
fd8b60 |
P_16_COPY(srcp->bitmaps[i], destp->bitmaps[i]);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
static void
|
|
Packit |
fd8b60 |
swap_header(hashp)
|
|
Packit |
fd8b60 |
HTAB *hashp;
|
|
Packit |
fd8b60 |
{
|
|
Packit |
fd8b60 |
HASHHDR *hdrp;
|
|
Packit |
fd8b60 |
int32_t i;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
hdrp = &hashp->hdr;
|
|
Packit |
fd8b60 |
|
|
Packit |
fd8b60 |
M_32_SWAP(hdrp->magic);
|
|
Packit |
fd8b60 |
M_32_SWAP(hdrp->version);
|
|
Packit |
fd8b60 |
M_32_SWAP(hdrp->lorder);
|
|
Packit |
fd8b60 |
M_32_SWAP(hdrp->bsize);
|
|
Packit |
fd8b60 |
M_32_SWAP(hdrp->bshift);
|
|
Packit |
fd8b60 |
M_32_SWAP(hdrp->ovfl_point);
|
|
Packit |
fd8b60 |
M_32_SWAP(hdrp->last_freed);
|
|
Packit |
fd8b60 |
M_32_SWAP(hdrp->max_bucket);
|
|
Packit |
fd8b60 |
M_32_SWAP(hdrp->high_mask);
|
|
Packit |
fd8b60 |
M_32_SWAP(hdrp->low_mask);
|
|
Packit |
fd8b60 |
M_32_SWAP(hdrp->ffactor);
|
|
Packit |
fd8b60 |
M_32_SWAP(hdrp->nkeys);
|
|
Packit |
fd8b60 |
M_32_SWAP(hdrp->hdrpages);
|
|
Packit |
fd8b60 |
M_32_SWAP(hdrp->h_charkey);
|
|
Packit |
fd8b60 |
for (i = 0; i < NCACHED; i++) {
|
|
Packit |
fd8b60 |
M_32_SWAP(hdrp->spares[i]);
|
|
Packit |
fd8b60 |
M_16_SWAP(hdrp->bitmaps[i]);
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
}
|
|
Packit |
fd8b60 |
#endif /* DB_BYTE_ORDER == DB_LITTLE_ENDIAN */
|