[alt.sources] lq-text Full Text Retrieval Database Part 12/13

lee@sq.sq.com (Liam R. E. Quin) (03/04/91)

: cut here --- cut here --
: To unbundle, sh this file
#! /bin/sh
: part 12
echo x - lq-text/src/ozmahash/db.3 1>&2
sed 's/^X//' >lq-text/src/ozmahash/db.3 <<'@@@End of lq-text/src/ozmahash/db.3'
X.\" Copyright (c) 1990 The Regents of the University of California.
X.\" All rights reserved.
X.\"
X.\" Redistribution and use in source and binary forms are permitted provided
X.\" that: (1) source distributions retain this entire copyright notice and
X.\" comment, and (2) distributions including binaries display the following
X.\" acknowledgement:  ``This product includes software developed by the
X.\" University of California, Berkeley and its contributors'' in the
X.\" documentation or other materials provided with the distribution and in
X.\" all advertising materials mentioning features or use of this software.
X.\" Neither the name of the University nor the names of its contributors may
X.\" be used to endorse or promote products derived from this software without
X.\" specific prior written permission.
X.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
X.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
X.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X.\"
X.\"	@(#)db.3	5.13 (Berkeley) 1/7/91
X.\"
X.TH DB 3  "January 7, 1991"
X.UC 7
X.SH NAME
Xbtree_open, hash_open, recno_open \- database access methods
X.SH SYNOPSIS
X.nf
X.ft B
X#include <sys/types.h>
X#include <db.h>
X
XDB *
Xbtree_open(const char *file, int flags, int mode, const BTREEINFO * openinfo);
X
XDB *
Xhash_open(const char *file, int flags, int mode, const HASHINFO * openinfo);
X
XDB *
Xrecno_open(const char *file, int flags, int mode, const RECNOINFO * openinfo);
X.ft R
X.fi
X.SH DESCRIPTION
X.IR Btree_open ,
X.IR hash_open ,
Xand
X.I recno_open
Xare access method interfaces to database files in btree, hashed, and
Xflat-file formats, respectively.
XThe btree format is a representation of a sorted, balanced tree structure.
XThe hashed format is an extensible, dynamic hashing scheme.
XThe flat-file format is a UNIX file with fixed or variable length
Xlines.
XThese formats are described in more detail below.
X.PP
XAccess to all file types is based on key/data pairs.
X.PP
XEach routine opens
X.I file
Xfor reading and/or writing.
XDatabases never intended to be preserved on disk may be created by setting
Xthe file parameter to NULL.
XThe
X.I flags
Xand
X.I mode arguments
Xare as specified to the
X.IR open (2)
Xroutine, however, only the O_CREAT, O_EXCL, O_RDONLY, O_RDWR, O_TRUNC
Xand O_WRONLY flags are meaningful.
XThe argument
X.I openinfo
Xis a pointer to an access method specific structure described below.
X.PP
XThe open routines return a pointer to a DB structure on success and NULL
Xon error.
XThe DB structure contains at least the following fields:
X.PP
Xtypedef struct {
X.RS
Xvoid *openinfo;
X.br
Xint (*close)(const DB *db);
X.br
Xint (*delete)(const DB *db, const DBT *key, u_long flag);
X.br
Xint (*get)(const DB *db, DBT *key, DBT *data, u_long flag);
X.br
Xint (*put)(const DB *db, const DBT *key, const DBT *data, u_long flag);
X.br
Xint (*seq)(const DB *db, DBT *key, DBT *data, u_long flag);
X.br
Xint (*sync)(const DB *db);
X.RE
X} DB;
X.PP
XThe elements of this structure consist of a pointer to an access method
Xspecific structure and a set of routines which perform various functions.
XAll of these routines take a pointer to a structure as returned by
Xone of the open routines, one or more pointers to key/data structures,
Xand, optionally, a flag value.
X.TP
Xopeninfo
XA pointer to an internal structure specific to the access method.
X.TP
Xclose
XA pointer to a routine to flush any cached information to disk, free any
Xallocated resources, and close the database file.
XSince key/data pairs may be cached in memory, failing to close the
Xfile with a
X.I close
Xroutine may result in inconsistent or lost information.
X.I Close
Xroutines return -1 on error (setting
X.IR errno )
Xand 0 on success.
X.TP
Xdelete
XA pointer to a routine to remove key/data pairs from the database.
X.I Delete
Xroutines return -1 on error (setting
X.IR errno ),
X0 on success, and 1 if the specified
X.I key
Xwas not in the file.
X.TP
Xget
XA pointer to a routine which is the interface for keyed retrieval from
Xthe database.
XThe address and length of the data associated with the specified
X.I key
Xare returned in the structure referenced by
X.IR data .
X.I Get
Xroutines return -1 on error (setting
X.IR errno ),
X0 on success, and 1 if the
X.I key
Xwas not in the file.
X.TP
Xput
XA pointer to a routine to store key/data pairs in the database.
X.IP
XThe parameter
X.I flag
Xmust be set to one of the following values:
X.RS
X.TP
XR_IAFTER
XAppend the data immediately after the data referenced by
X.IR key ,
Xcreating a new key/data pair.
X(This implies that the access method is able to create new keys,
Xi.e. the keys are ordered and independent, for example, record numbers.
XApplicable only to the
X.B RECNO
Xaccess method.)
X.TP
XR_IBEFORE
XInsert the data immediately before the data referenced by
X.IR key ,
Xcreating a new key/data pair.
X(This implies that the access method is able to create new keys,
Xi.e. the keys are ordered and independent, for example, record numbers.
XApplicable only to the
X.B RECNO
Xaccess method.)
X.TP
XR_NOOVERWRITE
XEnter the new key/data pair only if the key does not previously exist.
X.TP
XR_PUT
XEnter the new key/data pair and replace any previously existing key.
X.RE
X.IP
X.I Put
Xroutines return -1 on error (setting
X.IR errno ),
X0 on success, and 1 if the R_NOOVERWRITE
X.I flag
Xwas set and the key already exists in the file.
X.TP
Xseq
XA pointer to a routine which is the interface for sequential
Xretrieval from the database.
XThe address and length of the key are returned in the structure
Xreferenced by
X.IR key ,
Xand the address and length of the data are returned in the
Xstructure referenced
Xby
X.IR data .
X.IP
XSequential key/data pair retrieval may begin at any time, and the
Xposition of the ``cursor'' is not affected by calls to the
X.IR delete ,
X.IR get ,
X.IR put ,
Xor
X.I sync
Xroutines.
XModifications to the database during a sequential scan will be reflected
Xin the scan, i.e. records inserted behind the cursor will not be returned
Xwhile records inserted in front of the cursor will be returned.
X.IP
XThe flag value must be set to one of the following values:
X.RS
X.TP
XR_CURSOR
XThe data associated with the specified key is returned.
XThis differs from the
X.I get
Xroutines in that it sets the ``cursor'' to the location of the
Xkey as well.
X(This implies that the access method has a implicit order which does
Xnot change.
XApplicable only to the
X.B BTREE
Xand
X.B RECNO
Xaccess methods.)
X.TP
XR_FIRST
XThe first key/data pair of the database is returned.
X.TP
XR_LAST
XThe last key/data pair of the database is returned.
X(This implies that the access method has a implicit order which does
Xnot change.
XApplicable only to the
X.B BTREE
Xand
X.B RECNO
Xaccess methods.)
X.TP
XR_NEXT
XRetrieve the key/data pair immediately after the key/data pair most recently
Xretrieved using the
X.I seq
Xroutine.
XThe cursor is moved to the returned key/data pair.
XIf
X.I flag
Xis set to R_NEXT the first time the
X.I seq
Xroutine is called, the first key/data pair of the database is returned.
X.TP
XR_PREV
XRetrieve the key/data pair immediately before the key/data pair most recently
Xretrieved using the
X.I seq
Xroutine.
XThe cursor is moved to the returned key/data pair.
XIf
X.I flag
Xis set to R_PREV the first time the
X.I seq
Xroutine is called, the last key/data pair of the database is returned.
X(This implies that the access method has a implicit order which does
Xnot change.
XApplicable only to the
X.B BTREE
Xand
X.B RECNO
Xaccess methods.)
X.RE
X.IP
X.I Seq
Xroutines return -1 on error (setting
X.IR errno ),
X0 on success, 1 if there are no more key/data pairs available.
XIf the
X.B RECNO
Xaccess method is being used, and if the database file is a character special
Xfile and no complete key/data pairs are currently available, the
X.I seq
Xroutines return 2.
X.TP
Xsync
XA pointer to a routine to flush any cached information to disk.
XIf the database is in memory only, the
X.I sync
Xroutine has no effect and will always succeed.
X.I Sync
Xroutines return -1 on error (setting
X.IR errno )
Xand 0 on success.
X.SH "KEY/DATA PAIRS"
XAccess to all file types is based on key/data pairs.
XBoth keys and data are represented by the following data structure:
X.PP
Xtypedef struct {
X.RS
Xu_char *data;
X.br
Xsize_t size;
X.RE
X} DBT;
X.PP
XThe elements of the DBT structure are defined as follows:
X.TP
Xdata
XA pointer to a byte string.
X.TP
Xsize
XThe length of the byte string.
X.PP
XKey/data strings must fit into available memory.
X.SH BTREE
XOne of the access methods is a btree: a sorted, balanced tree structure
Xwith associated key/data pairs.
X.PP
XThe access method specific data structure provided to
X.I btree_open
Xis as follows:
X.PP
Xtypedef struct {
X.RS
Xu_long flags;
X.br
Xu_int psize;
X.br
Xu_int cachesize;
X.br
Xint (*compare)(const void *, const void *);
X.br
Xint lorder;
X.RE
X} BTREEINFO;
X.PP
XThe elements of this structure are defined as follows:
X.TP
Xflags
XThe flag value is specified by
X.IR or 'ing
Xany of the following values:
X.RS
X.TP
XR_DUP
XOn insertion,
Xif the key to be inserted already exists,
Xpermit insertion anyway.
XThis flag permits duplicate keys in the tree.
XBy default,
Xduplicates are not permitted,
Xand attempts to insert them will fail.
XNote, the order of retrieval of key/data pairs with duplicate keys is
Xundefined.
X.RE
X.TP
Xcachesize
XA suggested maximum size, in bytes, of the memory cache.
XSetting this value to zero specifies that an appropriate amount of memory
Xshould be used.
XSince every search examines the root page of the tree, caching the most
Xrecently used pages substantially improves access time.
XIn addition, physical writes are delayed as long as possible, so a moderate
Xcache can reduce the number of I/O operations significantly.
XObviously, using a cache increases the likelihood of corruption or lost data
Xif the system crashes while a tree is being modified.
XHowever, caching 10
Xpages decreases the creation time of a large tree by between two and three
Xorders of magnitude.
X.TP
Xcompare
XCompare is a user defined comparison function.
XIt must return an integer less than, equal to, or greater than zero if the
Xfirst argument is considered to be respectively less than, equal to, or
Xgreater than the second.
XThe same comparison function must be used on a given tree every time it
Xis opened.
XIf no comparison function is specified,
X.IR strcmp (3)
Xis used.
X.TP
Xlorder
XThe byte order for 4-byte integers in the stored database metadata.
XThe number should represent the order as an integer; for example, 
Xbig endian order would be the number 4,321.
XIf
X.I lorder
Xis 0 (no order is specified) the current host order is used.
XIf the  file already exists, the specified value is ignored and the
Xvalue specified when the tree was created is used.
X(Obviously, portability of the data forming the key/data pairs is the
Xconcern of the application program.)
X.TP
Xpsize
XPage size is the size in bytes of the pages used for nodes in the tree.
XIf the  file already exists, the specified value is ignored and the
Xvalue specified when the tree was created is used.
XIf
X.I psize
Xis zero, an appropriate page size is chosen (based on the system memory
Xand/or file system constraints), but will never be less than 512 bytes.
X.PP
XIf the pointer to the
X.I openinfo
Xdata structure is NULL, the
X.I btree_open
Xroutine will use appropriate values.
X.PP
XIf the database file already exists, and the O_TRUNC flag is not specified
Xto
X.IR btree_open ,
Xthe parameter
X.I psize
Xignored.
X.PP
XKey structures may reference byte strings of slightly less than one-half the
Xtree's page size only (see
X.IR psize ).
XData structures may reference byte strings of essentially unlimited length.
X.PP
XSearches, insertions, and deletions in a btree will all complete in
XO lg N.
X.PP
XForward sequential scans of a tree are from the least key to the greatest.
X.PP
XSpace freed up by deleting key/data pairs from a btree is never reclaimed,
Xalthough it is normally made available for reuse.
XThe exception to this is that space occupied by large data items (those
Xgreater than one quarter the size of a page) is neither reclaimed nor reused.
XThis means that the btree storage structure is grow-only.
XThe only solutions are to avoid excessive deletions, or to create a fresh
Xtree periodically from a scan of an existing one.
X.SH HASH
XOne of the access methods is hashed access and storage.
XThe access method specific data structure provided to
X.I hash_open
Xis as follows:
X.sp
Xtypedef struct {
X.RS
Xint bsize;
X.br
Xu_int cachesize;
X.br
Xint ffactor;
X.br
Xint nelem;
X.br
Xu_long (*hash)(const void *, const size_t);
X.br
Xint lorder;
X.RE
X} HASHINFO;
X.PP
XThe elements of this structure are defined as follows:
X.TP
Xbsize
X.I Bsize
Xdefines the hash table bucket size, and is, by default, 256 bytes.
XIt may be preferable to increase the page size for disk-resident tables and
Xtables with large data items.
X.TP
Xcachesize
XA suggested maximum size, in bytes, of the memory cache.
XSetting this value to zero specifies that an appropriate amount of memory
Xshould be used.
X.TP
Xffactor
X.I Ffactor
Xindicates a desired density within the hash table.
XIt is an approximation of the number of keys allowed to accumulate in any
Xone bucket, determining when the hash table grows or shrinks.
XThe default value is 8.
X.TP
Xhash
X.I Hash
Xis a user defined hash function.
XSince no hash function performs equally well on all possible data, the
Xuser may find that the built-in hash function does poorly on a particular
Xdata set.
XUser specified hash functions must take two arguments (a pointer to a byte
Xstring and a length) and return an u_long to be used as the hash value.
X.TP
Xlorder
XThe byte order for 4-byte integers in the stored database metadata.
XThe number should represent the order as an integer; for example, 
Xbig endian order would be the number 4,321.
XIf
X.I lorder
Xis 0 (no order is specified) the current host order is used.
XIf the  file already exists, the specified value is ignored and the
Xvalue specified when the tree was created is used.
X(Obviously, portability of the data forming the key/data pairs is the
Xconcern of the application program.)
X.TP
Xnelem
X.I Nelem
Xis an estimate of the final size of the hash table.
XIf not set, the default value is 1.
XIf not set or set too low, hash tables will expand gracefully as keys
Xare entered, although a slight performance degradation may be noticed.
X.PP
XIf the pointer to the
X.I openinfo
Xdata structure is NULL, the
X.I hash_open
Xroutine will use appropriate values.
X.PP
XIf the hash table already exists, and the O_TRUNC flag is not
Xspecified to
X.IR hash_open ,
Xthe parameters
X.IR bsize ,
X.IR ffactor ,
Xand
X.I nelem
Xare ignored.
X.PP
XIf a hash function is specified,
X.I hash_open
Xwill attempt to determine if the hash function specified is the same as
Xthe one with which the database was created, and will fail if it is not.
X.PP
XBoth key and data structures may reference byte strings of essentially
Xunlimited length.
X.PP
XBackward compatible interfaces to the routines described in
X.IR dbm (3),
X.IR hsearch (3),
Xand
X.IR ndbm (3)
Xare provided, however, these interfaces are not compatible with
Xprevious file formats.
X.SH RECNO
XOne of the access methods is either variable or fixed-length records,
Xthe former delimited by a specific byte value.
XThe access method specific data structure provided to
X.I recno_open
Xis as follows:
X.sp
Xtypedef struct {
X.RS
Xu_long flags;
X.br
Xu_int cachesize;
X.br
Xsize_t reclen;
X.br
Xu_char bval;
X.RE
X} RECNOINFO;
X.PP
XThe elements of this structure are defined as follows:
X.TP
Xflags
XThe flag value is specified by
X.IR or 'ing
Xany of the following values:
X.RS
X.TP
XR_FIXEDLEN
XThe records are fixed-length, not byte delimited.
XThe structure element
X.I reclen
Xspecifies the length of the record, and the structure element
X.I bval
Xis used as the pad character.
X.TP
XR_SNAPSHOT
XThis flag requires that a snapshot of the file be taken when
X.I recno_open
Xis called, instead of permitting any unmodified records to be
Xread from the original file.
X.RE
X.TP
Xcachesize
XA suggested maximum size, in bytes, of the memory cache.
XSetting this value to zero specifies that an appropriate amount of memory
Xshould be used.
X.TP
Xreclen
XThe length of a fixed-length record.
X.TP
Xbval
XThe delimiting byte to be used to mark the end of a record for
Xvariable-length records, and the pad character for fixed-length
Xrecords.
X.PP
XVariable-length and fixed-length data files require
X.I key
Xstructures to reference the following structure:
X.sp
Xtypedef struct {
X.RS
Xu_long length;
X.br
Xu_long number;
X.br
Xu_long offset;
X.br
Xu_char valid;
X.RE
X} RECNOKEY;
X.PP
XThe elements of this structure are defined as follows:
X.TP
Xlength
XThe length of the record.
X.TP
Xnumber
XThe record number.
X.TP
Xoffset
XThe offset in the file at which the record is located.
X.TP
Xvalid
XA flag value which indicates the validity of the other fields in the
Xstructure.
XThe flag value is specified by
X.IR or 'ing
Xone or more of the following values:
X.RS
X.TP
XR_LENGTH
XThe record length is valid.
X.TP
XR_NUMBER
XThe record number is valid.
X.TP
XR_OFFSET
XThe byte offset is valid.
X.RE
X.PP
XIf the record retrieval is successful, the record number, byte offset and
Xrecord length are set in the RECNOKEY structure referenced by the caller's
X.I key
Xstructure.
X.PP
XData structures may reference byte strings of essentially unlimited length.
X.SH ERRORS
XThe
X.I open
Xroutines may fail and set
X.I errno
Xfor any of the errors specified for the library routines
X.IR open (2)
Xand
X.IR malloc (3)
Xor the following:
X.TP
X[EINVAL]
XA parameter has been specified (hash function, pad byte etc.) that is
Xincompatible with the current file specification or there is a mismatch
Xbetween the version number of file and the software.
X.TP
X[EBADFORMAT]
XA file used by one of the
X.I open
Xroutines is incorrectly formatted.
X.PP
XThe
X.I close
Xroutines may fail and set
X.I errno
Xfor any of the errors specified for the library routines
X.IR close (2),
X.IR read (2),
X.IR write (2),
X.IR free (3),
Xor
X.IR fsync (2).
X.PP
XThe
X.IR delete ,
X.IR get ,
X.I put
Xand
X.I seq
Xroutines may fail and set
X.I errno
Xfor any of the errors specified for the library routines
X.IR read (2),
X.IR write (2),
X.IR free (3)
Xor
X.IR malloc (3).
X.PP
XThe
X.I sync
Xroutines may fail and set
X.I errno
Xfor any of the errors specified for the library routine
X.IR fsync (2).
X.SH "SEE ALSO"
X.IR "Dynamic Hash Tables" ,
XPer-Ake Larson, Communications of the ACM, April 1988.
X.br
X.IR "A New Hash Package for UNIX" ,
XMargo Seltzer, USENIX Proceedings, Winter 1991.
X.SH BUGS
XThe typedef DBT is a mnemonic for ``data base thang'', and was used
Xbecause noone could think of a reasonable name that wasn't already used.
X.PP
XNone of the access methods provide any form of concurrent access,
Xlocking, or transactions.
X.PP
XOnly big and little endian byte order is supported.
@@@End of lq-text/src/ozmahash/db.3
echo x - lq-text/src/ozmahash/db.h 1>&2
sed 's/^X//' >lq-text/src/ozmahash/db.h <<'@@@End of lq-text/src/ozmahash/db.h'
X/*-
X * Copyright (c) 1990 The Regents of the University of California.
X * All rights reserved.
X *
X * This code is derived from software contributed to Berkeley by
X * Margo Seltzer.
X *
X * %sccs.include.redist.c%
X *
X *	%W% (Berkeley) %G%
X */
X
X/* REMOVE THIS WHEN THIS GETS PUT ON A SYSTEM THAT HAS EFTYPE defined */
X#define	EFTYPE	EINVAL
X
X/* Magic Numbers */
X#define	HASHMAGIC	0x61561
X
X/* flags for DB.put() call */
X#define	R_APPEND	1		/* RECNO */
X#define	R_DUP		2		/* BTREE */
X#define	R_INSERT	3		/* RECNO */
X#define	R_NOOVERWRITE	4		/* BTREE, HASH, RECNO */
X
X/* flags for DB.seq() call */
X#define	R_CURSOR	1		/* BTREE, RECNO */
X#define	R_FIRST		2		/* BTREE, HASH, RECNO */
X#define	R_LAST		3		/* BTREE, RECNO */
X#define	R_NEXT		4		/* BTREE, HASH, RECNO */
X#define	R_PREV		5		/* BTREE, RECNO */
X
X/*
X    Swap between big/little endian
X*/
X
X#define BLSWAP(a) { \
X    long _tmp = a; \
X    ((char *)&(a))[0] = ((char *)&_tmp)[3]; \
X    ((char *)&(a))[1] = ((char *)&_tmp)[2]; \
X    ((char *)&(a))[2] = ((char *)&_tmp)[1]; \
X    ((char *)&(a))[3] = ((char *)&_tmp)[0]; \
X}
X
X#define BLSWAP_COPY(a,b) { \
X    ((char *)&(b))[0] = ((char *)&(a))[3]; \
X    ((char *)&(b))[1] = ((char *)&(a))[2]; \
X    ((char *)&(b))[2] = ((char *)&(a))[1]; \
X    ((char *)&(b))[3] = ((char *)&(a))[0]; \
X}
X#define BSSWAP(a) { \
X    u_short _tmp = (a); \
X    ((char *)&(a))[0] = ((char *)&_tmp)[1]; \
X    ((char *)&(a))[1] = ((char *)&_tmp)[0]; \
X}
X#define BSSWAP_COPY(a,b) { \
X    ((char *)&(b))[0] = ((char *)&(a))[1]; \
X    ((char *)&(b))[1] = ((char *)&(a))[0]; \
X}
X
X/* key/data structure -- a data-base thang */
Xtypedef struct {
X	char *data;
X	int size;
X} DBT;
X
X/* access method description structure */
Xtypedef struct {
X	char *internal;		/* access method private; really void * */
X	int (*close)();
X	int (*delete)();
X	int (*get)();
X	int (*put)();
X	int (*seq)();
X	int (*sync)();
X} DB;
X
X/* structure used to pass parameters to the hashing routines */
Xtypedef struct {
X	int bsize;		/* bucket size */
X	int ffactor;		/* fill factor */
X	int nelem;		/* number of elements */
X	int ncached;		/* bytes to cache */
X	int (*hash)();		/* hash function */
X	int lorder;		/* byte order */
X} HASHINFO;
X
X/* structure used to pass parameters to the btree routines */
Xtypedef struct {
X	int cachesize;		/* bytes to cache */
X	int psize;		/* page size */
X	int (*compare);		/* compare function */
X} BTREEINFO;
X
X/* structure used to pass parameters to the record routines */
Xtypedef struct {
X#define	R_FIXEDLEN	0x01	/* fixed-length records */
X	u_long flags;
X	int cachesize;		/* bytes to cache */
X	size_t reclen;		/* record length (fixed-length records) */
X	u_char bval;		/* delimiting byte (variable-length records */
X} RECNOINFO;
X
X/* key structure for the record routines */
Xtypedef struct {
X	u_long number;
X	u_long offset;
X	u_long length;
X#define	R_LENGTH	0x01	/* length is valid */
X#define	R_NUMBER	0x02	/* record number is valid */
X#define	R_OFFSET	0x04	/* offset is valid */
X	u_char valid;
X} RECNOKEY;
X
X#if __STDC__ || c_plusplus
XDB *btree_open(const char *file, int flags, int mode, const BTREEINFO *private);
XDB *hash_open(const char *file, int flags, int mode, const HASHINFO *private);
XDB *recno_open(const char *file, int flags, int mode, const RECNOINFO *private);
X#else
XDB *btree_open();
XDB *hash_open();
XDB *recno_open();
X#endif
@@@End of lq-text/src/ozmahash/db.h
echo x - lq-text/src/ozmahash/dynahash.c 1>&2
sed 's/^X//' >lq-text/src/ozmahash/dynahash.c <<'@@@End of lq-text/src/ozmahash/dynahash.c'
X/*-
X * Copyright (c) 1990 The Regents of the University of California.
X * All rights reserved.
X *
X * This code is derived from software contributed to Berkeley by
X * Margo Seltzer.
X *
X * %sccs.include.redist.c%
X */
X
X#if defined(LIBC_SCCS) && !defined(lint)
Xstatic char sccsid[] = "%W% (Berkeley) %G%";
X#endif /* LIBC_SCCS and not lint */
X
X#include	<sys/types.h>
X#include	<sys/file.h>
X#include	<sys/stat.h>
X#include	<errno.h>
X#include	<assert.h>
X#include	<string.h>
X#include	<db.h>
X#include	<hash.h>
X#include	<stdio.h>
X#include	<endian.h>
X
X/* For systems that do not haev O_ACCMODE */
X#ifndef O_ACCMODE
X#define	O_ACCMODE	(O_RDONLY|O_WRONLY|O_RDWR)
X#endif
X
X/* Fast arithmetic, relying on powers of 2, */
X
X#define MOD(x,y)		((x) & ((y)-1))
X#define RETURN_ERROR(ERR,LOC)	{ save_errno = ERR; goto LOC; }
X
X/* Return values */
X
X#define	SUCCESS	0
X#define	ERROR	-1
X#define	ABNORMAL 1
X
X/* external routines */
Xextern char *calloc();
X
X/* page.c */
Xextern int get_page();
Xextern int split_page();
Xextern int addel();
Xextern int delpair();
Xextern u_long *init_bitmap();
X
X/* big.c */
Xextern void big_return();
Xextern int big_keydata();
Xextern u_short find_last_page();
X
X/* buf.c */
Xextern BUFHEAD	*get_buf();
Xextern void buf_init();
Xextern int buf_free();
X
X/* hash function */
Xextern int (*default_hash)();
X
X/* My externals */
Xextern int expand_table();
Xextern int call_hash();
X
X/* Internal routines */
Xstatic HTAB *init_hash();
Xstatic int hash_access();
Xstatic int flush_meta();
Xstatic int alloc_segs();
Xstatic int init_htab();
Xstatic char *hash_realloc();
Xstatic int hdestroy();
Xstatic int hash_put();
Xstatic int hash_delete();
Xstatic int hash_get();
Xstatic int hash_sync();
Xstatic int hash_close();
Xstatic int hash_seq();
Xstatic void swap_header_copy();
Xstatic void swap_header();
X
X/* Local data */
X
XHTAB *hashp = NULL;
X
X#ifdef HASH_STATISTICS
Xlong hash_accesses, hash_collisions, hash_expansions, hash_overflows;
X#endif
X
X/************************** INTERFACE ROUTINES **********************/
X/* OPEN/CLOSE */
X
Xextern	DB *
Xhash_open ( file, flags, mode, info )
Xchar	*file;
Xint	flags;
Xint	mode;
XHASHINFO	*info;		/* Special directives for create */
X{
X    int		buckets;
X    int		bpages;
X    int		hdrsize;
X    int		i;
X    int		new_table = 0;
X    int		nkey;
X    int		nsegs;
X    int		save_errno;
X    struct	stat statbuf;
X    DB		*dbp;
X
X
X    if ( !(hashp = (HTAB *) calloc( 1, sizeof(HTAB) ))) {
X	/* calloc should set errno */
X	return(0);
X    }
X    /* 
X	Select flags relevant to us.
X	Even if user wants write only, we need to be able to read 
X	the actual file, so we need to open it read/write.  But, the
X	field in the hashp structure needs to be accurate so that
X	we can check accesses.
X    */
X    flags = flags & (O_CREAT | O_EXCL | O_RDONLY | O_RDWR | O_TRUNC | O_WRONLY);
X    hashp->flags = flags;
X    if ( flags & O_WRONLY )  flags = (flags & ~O_WRONLY) | O_RDWR;
X
X    if ( !file || 
X	 (flags & O_TRUNC) || 
X	 (stat ( file, &statbuf ) && (errno == ENOENT)) ) {
X	 new_table = 1;
X    }
X
X    if ( file && ((hashp->fp = open ( file, flags, mode )) == -1)) {
X	RETURN_ERROR (errno, error0);
X    }
X
X    if ( new_table ) {
X	if ( !(hashp = init_hash( info )) ) {
X	    RETURN_ERROR(errno,error1);
X	}
X    } else {
X	/* Table already exists */
X	if ( info && info->hash ) hashp->hash = info->hash;
X	else hashp->hash = default_hash;
X
X	hdrsize = read ( hashp->fp, &hashp->hdr, sizeof(HASHHDR) );
X#if BYTE_ORDER == LITTLE_ENDIAN
X	swap_header ( );
X#endif
X	if ( hdrsize == -1 ) {
X	    RETURN_ERROR(errno, error1);
X	}
X	if ( hdrsize != sizeof(HASHHDR) ) {
X	    RETURN_ERROR(EFTYPE, error1);
X	}
X
X	/* Verify file type, versions and hash function */
X	if ( hashp->MAGIC != HASHMAGIC ) 
X	    RETURN_ERROR ( EFTYPE, error1 );
X	if ( hashp->VERSION != VERSION_NO ) 
X	    RETURN_ERROR ( EFTYPE, error1 );
X	if (hashp->hash ( CHARKEY, sizeof(CHARKEY) ) != hashp->H_CHARKEY ) {
X	    RETURN_ERROR ( EFTYPE, error1 );
X	}
X
X	/* 
X	    Figure out how many segments we need.
X	*/
X	nsegs = (hashp->MAX_BUCKET + hashp->SGSIZE -1)/ hashp->SGSIZE;
X	hashp->nsegs = 0;
X	if (alloc_segs( nsegs )) {	
X	    /* 
X		If alloc_segs fails, table will have been destroyed 
X		and errno will have been set.
X	    */
X	    return( (DB *) NULL );
X	}
X
X	/* Read in bitmaps */
X	bpages = (hashp->SPARES[log2(hashp->MAX_BUCKET)] + 
X		  (hashp->BSIZE << BYTE_SHIFT) - 1) >> 
X		  (hashp->BSHIFT + BYTE_SHIFT);
X
X	hashp->mapp[0] = (u_long *)malloc(bpages<<hashp->BSHIFT);
X	if ( !hashp->mapp[0] ) {
X	    RETURN_ERROR(errno, error2);
X	}
X	for ( i = 0; i < bpages; i++ ) {
X	    hashp->mapp[i] = &hashp->mapp[0][i<<hashp->BSHIFT];
X	    if (get_page ((char *)hashp->mapp[i],  hashp->BITMAPS[i], 0, 1, 1)){
X		RETURN_ERROR(errno, error2);
X	    }
X	}
X
X    }
X
X    /* Initialize Buffer Manager */
X    if ( info && info->ncached ) {
X	buf_init (info->ncached);
X    } else {
X	buf_init (DEF_BUFSIZE);
X    }
X
X    hashp->new_file = new_table;
X    hashp->save_file = (file != NULL);
X    hashp->cbucket = -1;
X    if ( !(dbp = (DB *)malloc ( sizeof (DB) )) ) {
X	save_errno = errno;
X	hdestroy();
X	errno = save_errno;
X	return ( NULL );
X    }
X    dbp->internal = (char *)hashp;
X    dbp->close = hash_close;
X    dbp->delete = hash_delete;
X    dbp->get = hash_get;
X    dbp->put = hash_put;
X    dbp->seq = hash_seq;
X    dbp->sync = hash_sync;
X
X#ifdef DEBUG
X	(void)fprintf(stderr, "%s\n%s%x\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",
X		"init_htab:",
X		"TABLE POINTER   ", hashp,
X		"BUCKET SIZE     ", hashp->BSIZE,
X		"BUCKET SHIFT    ", hashp->BSHIFT,
X		"DIRECTORY SIZE  ", hashp->DSIZE,
X		"SEGMENT SIZE    ", hashp->SGSIZE,
X		"SEGMENT SHIFT   ", hashp->SSHIFT,
X		"FILL FACTOR     ", hashp->FFACTOR,
X		"MAX BUCKET      ", hashp->MAX_BUCKET,
X		"HIGH MASK       ", hashp->HIGH_MASK,
X		"LOW  MASK       ", hashp->LOW_MASK,
X		"NSEGS           ", hashp->nsegs,
X		"NKEYS           ", hashp->NKEYS );
X#endif
X#ifdef HASH_STATISTICS
X	hash_overflows = hash_accesses = hash_collisions = hash_expansions = 0;
X#endif
X    return (dbp);
X
Xerror2:
X    (void)hdestroy();
X    errno = save_errno;
X    hashp->errno = errno;
X    return ( (DB *)NULL );
X
Xerror1:
X    (void) close ( hashp->fp );
X
Xerror0:
X    free ( hashp );
X    errno = save_errno;
X    hashp->errno = errno;
X    return ( (DB *) NULL );
X}
X
Xstatic int
Xhash_close (dbp)
XDB	*dbp;
X{
X	if ( !dbp ) {
X	    return(ERROR);
X	}
X	hashp = (HTAB *)dbp->internal;
X	return (hdestroy());
X}
X
X
X/************************** LOCAL CREATION ROUTINES **********************/
Xstatic HTAB * 
Xinit_hash( info )
XHASHINFO *info;
X{
X	int	nelem;
X
X	nelem = 1;
X
X	hashp->LORDER	= BYTE_ORDER;
X	hashp->BSIZE    = DEF_BUCKET_SIZE;
X	hashp->BSHIFT   = DEF_BUCKET_SHIFT;
X	hashp->SGSIZE    = DEF_SEGSIZE;
X	hashp->SSHIFT   = DEF_SEGSIZE_SHIFT;
X	hashp->DSIZE    = DEF_DIRSIZE;
X	hashp->FFACTOR  = DEF_FFACTOR;
X	hashp->hash     = default_hash;
X	bzero (hashp->SPARES, sizeof (hashp->SPARES));
X
X	if ( info ) {
X	    if ( info->bsize )   {
X		/* Round pagesize up to power of 2 */
X		hashp->BSHIFT  = log2(info->bsize);
X		hashp->BSIZE   = 1 << hashp->BSHIFT;
X		if ( hashp->BSIZE > MAX_BSIZE ) {
X		    errno = EINVAL;
X		    return(0);
X		}
X	    }
X	    if ( info->ffactor )  hashp->FFACTOR = info->ffactor;
X	    if ( info->hash ) hashp->hash    = info->hash;
X	    if ( info->nelem ) nelem = info->nelem;
X	    if ( info->lorder ) {
X		if ( info->lorder != BIG_ENDIAN && 
X		     info->lorder != LITTLE_ENDIAN) {
X		    errno = EINVAL;
X		    return(0);
X		}
X		hashp->LORDER = info->lorder;
X	    }
X	}
X
X	/* init_htab should destroy the table and set errno if it fails */
X	if ( init_htab ( nelem ) ) {
X	    return(0);
X	} else {
X	    return(hashp);
X	}
X}
X
X/*
X    This calls alloc_segs which may run out of memory.
X    Alloc_segs will destroy the table and set errno,
X    so we just pass the error information along.
X
X    Returns 0 on No Error
X
X*/
Xstatic int
Xinit_htab ( nelem )
Xint	nelem;
X{
X	register SEGMENT	*segp;
X	register int nbuckets;
X	register int nsegs;
X	int	l2;
X
X /*
X  * Divide number of elements by the fill factor and determine a desired
X  * number of buckets.  Allocate space for the next greater power of
X  * two number of buckets
X  */
X	nelem = (nelem - 1) / hashp->FFACTOR + 1;
X
X	l2 = log2(nelem);
X	nbuckets = 1 << l2;
X	nbuckets = MAX ( nbuckets, 2 );
X
X	hashp->SPARES[l2] = l2 + 1;
X	hashp->SPARES[l2+1] = l2 + 1;
X	/* 
X	    First bitmap page is at:
X		splitpoint l2
X		page offset 1
X	*/
X	init_bitmap ( OADDR_OF(l2,1), l2+1, 0 );
X
X	hashp->MAX_BUCKET = hashp->LOW_MASK = nbuckets - 1;
X	hashp->HIGH_MASK = (nbuckets << 1) - 1;
X	hashp->HDRPAGES = ((MAX(sizeof(HASHHDR),MINHDRSIZE) - 1) >> 
X			  hashp->BSHIFT) + 1;
X
X	nsegs = (nbuckets - 1) / hashp->SGSIZE + 1;
X	nsegs = 1 << log2(nsegs);
X
X	if ( nsegs > hashp->DSIZE ) {
X	    hashp->DSIZE  = nsegs;
X	}
X
X	return (alloc_segs ( nsegs ) );
X}
X
X/********************** DESTROY/CLOSE ROUTINES ************************/
X
X/*
X    Flushes any changes to the file if necessary and
X    destroys the hashp structure, freeing all allocated
X    space.
X*/
Xstatic int
Xhdestroy()
X{
X	int	save_errno;
X	int	i;
X
X	save_errno = 0;
X
X	if (hashp != NULL) {
X#ifdef HASH_STATISTICS
X	 (void)	fprintf(stderr,	"hdestroy: accesses %ld collisions %ld\n",
X			hash_accesses, hash_collisions);
X	 (void)	fprintf(stderr, "hdestroy: expansions %ld\n",
X			hash_expansions);
X	 (void)	fprintf(stderr, "hdestroy: overflows %ld\n",
X			hash_overflows);
X	 (void)	fprintf(stderr,	"keys %ld maxp %d segmentcount %d\n",
X			hashp->NKEYS, hashp->MAX_BUCKET, hashp->nsegs);
X
X	for ( i = 0; i < NCACHED; i++ ) {
X	    (void) fprintf ( stderr, "spares[%d] = %d\n", i, hashp->SPARES[i] );
X	}
X#endif
X
X		/* 
X		    Call on buffer manager to free buffers, and if
X		    required, write them to disk
X		*/
X		if (buf_free(1, hashp->save_file)) {
X		    save_errno = errno;
X		}
X		if ( hashp->dir ) {
X		    (void)free(*hashp->dir);	/* Free initial segments */
X		    /* Free extra segments */
X		    while ( hashp->exsegs-- ) {
X			(void)free ( hashp->dir[--hashp->nsegs] );
X		    }
X		    (void)free(hashp->dir);
X		}
X		if (flush_meta() && !save_errno) {
X		    save_errno = errno;
X		}
X		if ( hashp->save_file ) (void)close (hashp->fp);
X		(void)free(hashp);
X		hashp = NULL;
X	}
X	if ( save_errno ) {
X	    errno = save_errno;
X	    return(ERROR);
X	} else {
X	    return(SUCCESS);
X	}
X}
X
X/* 
X    Write modified pages to disk 
X    0 == OK
X    -1 ERROR
X*/
Xstatic int
Xhash_sync(dbp)
XDB	*dbp;
X{
X	if ( !dbp ) {
X	    return (ERROR);
X	}
X
X	hashp = (HTAB *)dbp->internal;
X
X	if (!hashp->save_file) return(0);
X	if ( buf_free ( 0, 1 )  || flush_meta()) {
X	    return(ERROR);
X	}
X	hashp->new_file = 0;
X	return(0);
X}
X
X/*
X0 == OK
X-1 indicates that errno should be set
X*/
Xstatic int
Xflush_meta()
X{
X    	int	fp;
X	int	hdrsize;
X	int	i;
X	int	wsize;
X	HASHHDR	*whdrp;
X	HASHHDR	whdr;
X
X	if (!hashp->save_file) return(0);
X	hashp->MAGIC = HASHMAGIC;
X	hashp->VERSION = VERSION_NO;
X	hashp->H_CHARKEY = hashp->hash ( CHARKEY, sizeof(CHARKEY));
X
X	fp = hashp->fp;
X	whdrp = &hashp->hdr;
X#if BYTE_ORDER == LITTLE_ENDIAN
X	whdrp = &whdr;
X	swap_header_copy( &hashp->hdr, whdrp );
X#endif
X	if ( (lseek (fp, 0, L_SET) == -1 ) ||
X	     ((wsize = write ( fp, whdrp, sizeof(HASHHDR))) == -1)) {
X	    return(-1);
X	} else if ( wsize != sizeof(HASHHDR) ) {
X	    errno = EFTYPE;
X	    hashp->errno = errno;
X	    return(-1);
X	}
X	for ( i = 0; i < NCACHED; i++ ) {
X	    if ( hashp->mapp[i] ) {
X		if (!put_page((char *)hashp->mapp[i], hashp->BITMAPS[i], 0, 1)){
X		    return(-1);
X		}
X	    }
X	}
X	return(0);
X}
X/*******************************SEARCH ROUTINES *****************************/
X/*
X    All the access routines return 
X	0 on SUCCESS
X	1 to indicate an external ERROR (i.e. key not found, etc)
X	-1 to indicate an internal ERROR (i.e. out of memory, etc)
X*/
Xstatic int
Xhash_get ( dbp, key, data )
XDB	*dbp;
XDBT *key, *data;
X{
X    if ( !dbp ) {
X	return (ERROR);
X    }
X    hashp = (HTAB *)dbp->internal;
X    if ( hashp->flags & O_WRONLY ) {
X	errno = EBADF;
X	hashp->errno = errno;
X	return ( ERROR );
X    }
X    return ( hash_access ( HASH_GET, key, data ) );
X}
X
Xstatic int
Xhash_put ( dbp, key, data, flag )
XDB	*dbp;
XDBT 	*key, *data;
Xint	flag;
X{
X    if ( !dbp ) {
X	return (ERROR);
X    }
X    hashp = (HTAB *)dbp->internal;
X    if ( (hashp->flags & O_ACCMODE) == O_RDONLY ) {
X	errno = EBADF;
X	hashp->errno = errno;
X	return ( ERROR );
X    }
X    if ( flag == R_NOOVERWRITE ) {
X	return ( hash_access ( HASH_PUTNEW, key, data ) );
X    } else {
X	return ( hash_access ( HASH_PUT, key, data ) );
X    }
X}
X
Xstatic int
Xhash_delete ( dbp, key, flags )
XDB	*dbp;
XDBT 	*key;
Xint	flags;		/* Ignored */
X{
X    if ( !dbp ) {
X	return (ERROR);
X    }
X    hashp = (HTAB *)dbp->internal;
X    if ( (hashp->flags & O_ACCMODE) == O_RDONLY ) {
X	errno = EBADF;
X	hashp->errno = errno;
X	return ( ERROR );
X    }
X    return ( hash_access ( HASH_DELETE, key, NULL ) );
X}
X
X/*
X    Assume that hashp has been set in wrapper routine
X*/
Xstatic int
Xhash_access(action, key, val)
XACTION action;
XDBT *key, *val;
X{
X	register	BUFHEAD	*rbufp;
X	register	u_short	*bp;
X	register	int	ndx;
X	register 	int n;
X	register 	int off = hashp->BSIZE;
X	register	int		size;
X	register	char	*kp;
X	BUFHEAD	*bufp;
X	u_short	pageno;
X
X#ifdef HASH_STATISTICS
X	hash_accesses++;
X#endif
X
X	size = key->size;
X	kp = key->data;
X	rbufp = get_buf ( call_hash(key->data, size), NULL, 0 );
X	if ( !rbufp ) return(ERROR);
X
X	for ( bp = (u_short *)rbufp->page, n = *bp++, ndx = 1; ndx < n;  ) {
X	    if ( bp[1] >= REAL_KEY ) {
X		/* Real key/data pair */
X		if (size == off - *bp && 
X		    bcmp(kp, rbufp->page + *bp, size) == 0) {
X		    goto found;
X		}
X		off = bp[1];
X#ifdef HASH_STATISTICS
X		hash_collisions++;
X#endif
X	        bp += 2; 
X	        ndx += 2;
X	    } else if ( bp[1] == OVFLPAGE ) {
X		rbufp = get_buf ( *bp, rbufp, 0 );
X		if ( !rbufp ) return (ERROR);
X		/* FOR LOOP INIT */
X		bp = (u_short *)rbufp->page;
X		n = *bp++;
X		ndx = 1;
X		off = hashp->BSIZE;
X	    } else if ( bp[1] < REAL_KEY ) {
X		if ( (ndx = find_bigpair(rbufp, ndx, kp, size )) > 0 ) {
X		    goto found;
X		} else if ( ndx == -2 ) {
X		    bufp = rbufp;
X		    if ( !(pageno = find_last_page ( &bufp )) ) {
X			ndx = 0;
X			rbufp = bufp;
X			break;	/* FOR */
X		    }
X		    rbufp = get_buf ( pageno, bufp, 0 );
X		    if ( !rbufp ) return (ERROR);
X		    /* FOR LOOP INIT */
X		    bp = (u_short *)rbufp->page;
X		    n = *bp++;
X		    ndx = 1;
X		    off = hashp->BSIZE;
X		} else  {
X		    return(ERROR);
X		}
X	    } 
X	}
X
X	/* Not found */
X	switch ( action ) {
X	    case HASH_PUT:
X	    case HASH_PUTNEW:
X		if (addel(rbufp, key, val)) {
X		    return(ERROR);
X		} else {
X		    return(SUCCESS);
X		}
X	    case HASH_GET:
X		return ( ABNORMAL );
X	    case HASH_DELETE:
X		return ( ABNORMAL );
X	    default:
X		return(ABNORMAL);
X	}
X
Xfound:
X	switch (action) {
X	    case HASH_PUTNEW:
X		return(ABNORMAL);
X	    case HASH_GET:
X		bp = (u_short *)rbufp->page;
X		if (bp[ndx+1] < REAL_KEY) big_return(rbufp, ndx, val, 0);
X		else {
X		    val->data = rbufp->page + (int) bp[ndx + 1];
X		    val->size = bp[ndx] - bp[ndx + 1];
X		}
X		break;
X	    case HASH_PUT:
X		if (delpair (rbufp, ndx))return(ERROR);
X		if (addel (rbufp, key, val)) return(ERROR);
X		break;
X	    case HASH_DELETE:
X		if (delpair (rbufp, ndx))return(ERROR);
X		break;
X	}
X	return (SUCCESS);
X}
X
Xstatic int
Xhash_seq(dbp, key, data, flag)
XDB	*dbp;
XDBT 	*key, *data;
Xint flag;
X{
X	register	int bucket;
X	register	BUFHEAD	*bufp;
X	u_short	*bp;
X	u_short	ndx;
X	u_short	pageno;
X
X	if ( !dbp ) {
X	    return (ERROR);
X	}
X
X	hashp = (HTAB *)dbp->internal;
X	if ( hashp->flags & O_WRONLY ) {
X	    errno = EBADF;
X	    hashp->errno = errno;
X	    return ( ERROR );
X	}
X#ifdef HASH_STATISTICS
X	hash_accesses++;
X#endif
X
X	if ( (hashp->cbucket < 0) || (flag == R_FIRST) ) {
X	    hashp->cbucket = 0;
X	    hashp->cndx = 1;
X	    hashp->cpage = NULL;
X	}
X
X	if ( !(bufp = hashp->cpage) ) {
X	    for (bucket = hashp->cbucket; 
X		 bucket < hashp->MAX_BUCKET; 
X		 bucket++, hashp->cndx = 1 ) {
X
X		bufp = get_buf ( bucket, NULL, 0 );
X		if (!bufp) return(ERROR);
X		hashp->cpage = bufp;
X		bp = (u_short *)bufp->page;
X		if (bp[0]) break;
X	    }
X	    hashp->cbucket = bucket;
X	    if ( hashp->cbucket >= hashp->MAX_BUCKET ) {
X		hashp->cbucket = -1;
X		return ( ABNORMAL );
X	    } 
X	} else {
X	    bp  = (u_short *)hashp->cpage->page;
X	}
X	
X#ifdef DEBUG
X	assert (bp);
X	assert (bufp);
X#endif
X	while ( bp[hashp->cndx+1] == OVFLPAGE ) {
X	    bufp = hashp->cpage = get_buf ( bp[hashp->cndx], bufp, 0 );
X	    if (!bufp) return(ERROR);
X	    bp = (u_short *)(bufp->page);
X	    hashp->cndx = 1;
X	}
X	ndx = hashp->cndx;
X	if (bp[ndx+1] < REAL_KEY) {
X	    if (big_keydata(bufp, ndx, key, data, 1)) {
X		return(ERROR);
X	    }
X	} else {
X	    key->data = hashp->cpage->page + bp[ndx];
X	    key->size = (ndx > 1 ? bp[ndx-1] : hashp->BSIZE) - bp[ndx];
X	    data->data = hashp->cpage->page + bp[ndx + 1];
X	    data->size = bp[ndx] - bp[ndx + 1];
X	    ndx += 2;
X	    if ( ndx > bp[0] ) {
X		hashp->cpage = NULL;
X		hashp->cbucket++;
X		hashp->cndx=1;
X	    } else hashp->cndx = ndx;
X	}
X	return (SUCCESS);
X}
X
X/********************************* UTILITIES ************************/
X/*
X    0 ==> OK
X    -1 ==> Error
X*/
Xextern int
Xexpand_table()
X{
X	int	old_bucket, new_bucket;
X	int	new_segnum;
X	int	dirsize;
X	int	spare_ndx;
X	register	char **old, **new;
X#ifdef HASH_STATISTICS
X	hash_expansions++;
X#endif
X
X	new_bucket = ++hashp->MAX_BUCKET;
X	old_bucket = (hashp->MAX_BUCKET & hashp->LOW_MASK);
X
X	new_segnum = new_bucket >> hashp->SSHIFT;
X
X	/* Check if we need a new segment */
X	if ( new_segnum >= hashp->nsegs ) {
X
X	    /* Check if we need to expand directory */
X	    if ( new_segnum >= hashp->DSIZE ) {
X
X		/* Reallocate directory */
X		dirsize = hashp->DSIZE * sizeof ( SEGMENT * );
X		if (!hash_realloc ( &hashp->dir, dirsize, (dirsize << 1 ) )) {
X		    return(-1);
X		}
X		hashp->DSIZE = dirsize << 1;
X	    }
X	    if (!(hashp->dir[new_segnum] = 
X		    (SEGMENT)calloc ( hashp->SGSIZE, sizeof(SEGMENT)))) {
X		    return(-1);
X	    }
X	    hashp->exsegs++;
X	    hashp->nsegs++;
X	}
X
X	/*
X	    If the split point is increasing (MAX_BUCKET's log
X	    base 2 increases), we need to copy the current contents
X	    of the spare split bucket to the next bucket
X	*/
X	spare_ndx = log2(hashp->MAX_BUCKET);
X	if ( spare_ndx != (log2(hashp->MAX_BUCKET - 1))) {
X	    hashp->SPARES[spare_ndx] = hashp->SPARES[spare_ndx-1];
X	}
X
X	if ( new_bucket > hashp->HIGH_MASK ) {
X	    /* Starting a new doubling */
X	    hashp->LOW_MASK = hashp->HIGH_MASK;
X	    hashp->HIGH_MASK = new_bucket | hashp->LOW_MASK;
X	}
X
X	/*
X	 * Relocate records to the new bucket
X	 */
X	return(split_page ( old_bucket, new_bucket ));
X}
X/*
X    If realloc guarantees that the pointer is not destroyed
X    if the realloc fails, then this routine can go away
X*/
Xstatic char * 
Xhash_realloc ( p_ptr, oldsize, newsize )
Xchar	**p_ptr;
Xint	oldsize;
Xint	newsize;
X{
X	register char	*p;
X
X	if (p = (char *)malloc ( newsize ) ) {
X		bcopy ( *p_ptr, p, oldsize );
X		bzero ( *p_ptr + oldsize, newsize-oldsize );
X		free(*p_ptr);
X		*p_ptr = p;
X	}
X	return (p);
X}
X
Xextern int
Xcall_hash ( k, len )
Xchar	*k;
Xint	len;
X{
X	int	n, bucket;
X	n = hashp->hash(k, len);
X
X	bucket = n & hashp->HIGH_MASK;
X	if ( bucket > hashp->MAX_BUCKET ) {
X	    bucket = bucket & hashp->LOW_MASK;
X	}
X
X	return(bucket);
X}
X
X/*
X    Allocate segment table.  On error, destroy the table
X    and set errno.
X
X    Returns 0 on success
X*/
Xstatic int
Xalloc_segs ( nsegs )
Xint	nsegs;
X{
X    register int	i;
X    register SEGMENT	store;
X
X    int	save_errno;
X
X    if (!(hashp->dir = (SEGMENT *)calloc(hashp->DSIZE, sizeof(SEGMENT *)))) {
X	save_errno = errno;
X	(void)hdestroy();
X	errno = save_errno;
X	return(-1);
X    }
X
X    /* Allocate segments */
X    store = (SEGMENT)calloc ( nsegs << hashp->SSHIFT, sizeof (SEGMENT) );
X    if ( !store ) {
X	save_errno = errno;
X	(void)hdestroy();
X	errno = save_errno;
X	return(-1);
X    }
X
X    for ( i=0; i < nsegs; i++, hashp->nsegs++ ) {
X	hashp->dir[i] = &store[i<<hashp->SSHIFT];
X    }
X    return(0);
X}
X
X/*
X    Hashp->hdr needs to be byteswapped.
X*/
Xstatic void
Xswap_header_copy ( srcp, destp )
XHASHHDR	*srcp;
XHASHHDR	*destp;
X{
X    int i;
X
X    BLSWAP_COPY(srcp->magic, destp->magic);
X    BLSWAP_COPY(srcp->version, destp->version);
X    BLSWAP_COPY(srcp->lorder, destp->lorder);
X    BLSWAP_COPY(srcp->bsize, destp->bsize);
X    BLSWAP_COPY(srcp->bshift, destp->bshift);
X    BLSWAP_COPY(srcp->dsize, destp->dsize);
X    BLSWAP_COPY(srcp->ssize, destp->ssize);
X    BLSWAP_COPY(srcp->sshift, destp->sshift);
X    BLSWAP_COPY(srcp->max_bucket, destp->max_bucket);
X    BLSWAP_COPY(srcp->high_mask, destp->high_mask);
X    BLSWAP_COPY(srcp->low_mask, destp->low_mask);
X    BLSWAP_COPY(srcp->ffactor, destp->ffactor);
X    BLSWAP_COPY(srcp->nkeys, destp->nkeys);
X    BLSWAP_COPY(srcp->hdrpages, destp->hdrpages);
X    BLSWAP_COPY(srcp->h_charkey, destp->h_charkey);
X    for ( i=0; i < NCACHED; i++ ) {
X	BLSWAP_COPY ( srcp->spares[i] , destp->spares[i]);
X	BSSWAP_COPY ( srcp->bitmaps[i] , destp->bitmaps[i]);
X    }
X    return;
X}
X
Xstatic void
Xswap_header ( )
X{
X    HASHHDR	*hdrp;
X    int	i;
X
X    hdrp = &hashp->hdr;
X
X    BLSWAP(hdrp->magic);
X    BLSWAP(hdrp->version);
X    BLSWAP(hdrp->lorder);
X    BLSWAP(hdrp->bsize);
X    BLSWAP(hdrp->bshift);
X    BLSWAP(hdrp->dsize);
X    BLSWAP(hdrp->ssize);
X    BLSWAP(hdrp->sshift);
X    BLSWAP(hdrp->max_bucket);
X    BLSWAP(hdrp->high_mask);
X    BLSWAP(hdrp->low_mask);
X    BLSWAP(hdrp->ffactor);
X    BLSWAP(hdrp->nkeys);
X    BLSWAP(hdrp->hdrpages);
X    BLSWAP(hdrp->h_charkey);
X    for ( i=0; i < NCACHED; i++ ) {
X	BLSWAP ( hdrp->spares[i] );
X	BSSWAP ( hdrp->bitmaps[i] );
X    }
X    return;
X}
@@@End of lq-text/src/ozmahash/dynahash.c
echo x - lq-text/src/ozmahash/endian.h 1>&2
sed 's/^X//' >lq-text/src/ozmahash/endian.h <<'@@@End of lq-text/src/ozmahash/endian.h'
X/*
X * Copyright (c) 1987 Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms are permitted provided
X * that: (1) source distributions retain this entire copyright notice and
X * comment, and (2) distributions including binaries display the following
X * acknowledgement:  ``This product includes software developed by the
X * University of California, Berkeley and its contributors'' in the
X * documentation or other materials provided with the distribution and in
X * all advertising materials mentioning features or use of this software.
X * Neither the name of the University nor the names of its contributors may
X * be used to endorse or promote products derived from this software without
X * specific prior written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
X * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
X * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X *
X *	@(#)endian.h	7.5 (Berkeley) 5/8/90
X */
X
X/*
X * Definitions for byte order,
X * according to byte significance from low address to high.
X */
X#define	LITTLE_ENDIAN	1234	/* least-significant byte first (vax) */
X#define	BIG_ENDIAN	4321	/* most-significant byte first (IBM, net) */
X#define	PDP_ENDIAN	3412	/* LSB first in word, MSW first in long (pdp) */
X
X#define	BYTE_ORDER	LITTLE_ENDIAN	/* byte order on DECSTATION */
X
X/*
X * Macros for network/external number representation conversion.
X */
X#if BYTE_ORDER == BIG_ENDIAN && !defined(lint)
X#define	ntohl(x)	(x)
X#define	ntohs(x)	(x)
X#define	htonl(x)	(x)
X#define	htons(x)	(x)
X
X#define	NTOHL(x)	(x)
X#define	NTOHS(x)	(x)
X#define	HTONL(x)	(x)
X#define	HTONS(x)	(x)
X
X#else
X
Xunsigned short	ntohs(), htons();
Xunsigned long	ntohl(), htonl();
X
X#define	NTOHL(x)	(x) = ntohl(x)
X#define	NTOHS(x)	(x) = ntohs(x)
X#define	HTONL(x)	(x) = htonl(x)
X#define	HTONS(x)	(x) = htons(x)
X#endif
X
@@@End of lq-text/src/ozmahash/endian.h
echo end of part 12
-- 
Liam R. E. Quin,  lee@sq.com, SoftQuad Inc., Toronto, +1 (416) 963-8337