Clean up deleted files.

This commit is contained in:
mycroft 1993-06-14 21:16:14 +00:00
parent 68028dc2de
commit 6609149bb3
16 changed files with 0 additions and 17795 deletions

View File

@ -1,383 +0,0 @@
/*-
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Olson.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)big.c 5.2 (Berkeley) 2/22/91";
#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
#include <db.h>
#include <stdlib.h>
#include <string.h>
#include "btree.h"
/*
* _BT_GETBIG -- Get big data from indirect pages.
*
* This routine chases indirect blocks for the big object at the
* specified page to a buffer, and return the address of the buffer.
*
* Parameters:
* t -- btree with the indirect blocks
* pgno -- page number that starts the chain
* p -- (char **) to get the address of the buffer containing
* the key or datum.
* sz -- pointer to an int to get the size of the instantiated
* object.
*
* Returns:
* RET_SUCCESS, RET_ERROR.
*
* Side Effects:
* None.
*/
int
_bt_getbig(t, pgno, p, sz)
BTREE_P t;
pgno_t pgno;
char **p;
int *sz;
{
pgno_t save;
size_t nbytes;
size_t nhere;
BTHEADER *h;
char *top, *from, *where;
save = t->bt_curpage->h_pgno;
if (_bt_getpage(t, pgno) == RET_ERROR)
return (RET_ERROR);
h = t->bt_curpage;
bcopy((char *) &(h->h_linp[0]),
(char *) &nbytes,
(size_t) sizeof(nbytes));
if ((*p = (char *) malloc(nbytes)) == (char *) NULL)
return (RET_ERROR);
*sz = nbytes;
from = ((char *) (&h->h_linp[0])) + sizeof(nbytes);
top = ((char *) h) + t->bt_psize;
/* need more space for data? */
where = *p;
while (nbytes > 0) {
nhere = (int) (top - from);
if (nhere > nbytes) {
(void) bcopy(from, where, (size_t) nbytes);
nbytes = 0;
} else {
(void) bcopy(from, where, nhere);
where += nhere;
nbytes -= nhere;
if (_bt_getpage(t, h->h_nextpg) == RET_ERROR)
return (RET_ERROR);
h = t->bt_curpage;
top = ((char *) h) + t->bt_psize;
from = (char *) &(h->h_linp[0]);
}
}
if (_bt_getpage(t, save) == RET_ERROR)
return (RET_ERROR);
return (RET_SUCCESS);
}
/*
* _BT_DELINDIR -- Delete a chain of indirect blocks from the btree.
*
* When a large item is deleted from the tree, this routine puts the
* space that it occupied onto the free list for later reuse. The
* bt_free entry in the btree structure points at the head of this list.
* This value is also stored on disk in the btree's metadata.
*
* Parameters:
* t -- btree from which to delete pages
* chain -- page number that starts the chain.
*
* Returns:
* RET_SUCCESS, RET_ERROR.
*
* Side Effects:
* Invalidates the current on-disk version of the btree's
* metadata (if any), and updates the free list appropriately.
*/
int
_bt_delindir(t, chain)
BTREE_P t;
pgno_t chain;
{
BTHEADER *h;
pgno_t save;
pgno_t oldfree;
h = t->bt_curpage;
save = h->h_pgno;
if (_bt_getpage(t, chain) == RET_ERROR)
return (RET_ERROR);
/*
* If some internal node is pointing at this chain, don't
* delete it.
*/
if (t->bt_curpage->h_flags & F_PRESERVE) {
if (_bt_getpage(t, save) == RET_ERROR)
return (RET_ERROR);
return (RET_SUCCESS);
}
/* if there's nothing on the free list, this is easy... */
if (t->bt_free == P_NONE) {
t->bt_free = chain;
} else {
oldfree = t->bt_free;
/* find the end of the data chain for the deleted datum */
t->bt_free = chain;
do {
if (_bt_getpage(t, chain) == RET_ERROR)
return (RET_ERROR);
h = t->bt_curpage;
if (h->h_nextpg != P_NONE)
chain = h->h_nextpg;
} while (h->h_nextpg != P_NONE);
/* link freed pages into free list */
h->h_nextpg = oldfree;
if (_bt_write(t, h, RELEASE) == RET_ERROR)
return (RET_ERROR);
if (_bt_getpage(t, oldfree) == RET_ERROR)
return (RET_ERROR);
h = t->bt_curpage;
h->h_prevpg = chain;
if (_bt_write(t, h, RELEASE) == RET_ERROR)
return (RET_ERROR);
}
/* restore the tree's current page pointer */
if (_bt_getpage(t, save) == RET_ERROR)
return (RET_ERROR);
/* we have trashed the tree metadata; rewrite it later */
t->bt_flags &= ~BTF_METAOK;
return (RET_SUCCESS);
}
/*
* _BT_INDIRECT -- Write a series of indirect pages for big objects.
*
* A chain of indirect pages looks like
*
* +-------------------+ +---------------------+
* |hdr|size| | |hdr| |
* +---+----+ | +---+ |
* | ... data ... | | ... data ... | ...
* | | | |
* +-------------------+ +---------------------+
*
* where hdr is a standard btree page header (with the indirect bit
* set), size on the first page is the real size of the datum, and
* data are bytes of the datum, split across as many pages as necessary.
* Indirect pages are chained together with the h_prevpg and h_nextpg
* entries of the page header struct.
*
* A single DBT is written per chain, so space on the last page is
* wasted.
*
* We return the page number of the start of the chain.
*
* When a big object is deleted from a tree, the space that it occupied
* is placed on a free list for later reuse. This routine checks that
* free list before allocating new pages to the big datum being inserted.
*
* Parameters:
* t -- btree in which to store indirect blocks
* data -- DBT with the big datum in it
* pgno -- place to put the starting page number of the chain
*
* Returns:
* RET_SUCCESS, RET_ERROR.
*
* Side Effects:
* Current page is changed on return.
*/
int
_bt_indirect(t, data, pgno)
BTREE_P t;
DBT *data;
pgno_t *pgno;
{
pgno_t prev;
char *top;
char *where;
char *from;
size_t dsize;
pgno_t nextchn;
int ischain;
BTHEADER *cur;
/* get set for first page in chain */
prev = P_NONE;
dsize = data->size;
from = (char *) data->data;
/* if there are blocks on the free list, use them first */
if ((*pgno = t->bt_free) == P_NONE) {
if ((cur = _bt_allocpg(t)) == (BTHEADER *) NULL)
return (RET_ERROR);
ischain = 0;
*pgno = cur->h_pgno = ++(t->bt_npages);
} else {
if (_bt_getpage(t, *pgno) == RET_ERROR)
return (RET_ERROR);
ischain = 1;
cur = t->bt_curpage;
}
cur->h_flags = F_CONT|F_LEAF;
(void) bcopy((char *) &dsize, (char *) &cur->h_linp[0], sizeof(size_t));
where = ((char *) (&cur->h_linp[0])) + sizeof(size_t);
/* fill and write pages in the chain */
for (;;) {
int nhere;
top = ((char *) cur) + t->bt_psize;
cur->h_prevpg = prev;
nextchn = cur->h_nextpg;
nhere = (int) (top - where);
if (nhere >= dsize) {
(void) bcopy(from, where, (int) dsize);
cur->h_nextpg = P_NONE;
dsize = 0;
} else {
(void) bcopy(from, where, (int) nhere);
dsize -= nhere;
from += nhere;
if (nextchn == P_NONE)
cur->h_nextpg = t->bt_npages + 1;
prev = cur->h_pgno;
}
/* current page is ready to go; write it out */
if (_bt_write(t, cur, RELEASE) == RET_ERROR)
return (RET_ERROR);
/* free the current page, if appropriate */
if (ISDISK(t) && !ISCACHE(t) && !ischain) {
(void) free ((char *) cur);
}
/* done? */
if (dsize == 0)
break;
/* allocate another page */
if (nextchn == P_NONE) {
if ((cur = _bt_allocpg(t)) == (BTHEADER *) NULL)
return (RET_ERROR);
ischain = 0;
cur->h_pgno = ++(t->bt_npages);
} else {
if (_bt_getpage(t, nextchn) == RET_ERROR)
return (RET_ERROR);
ischain = 1;
cur = t->bt_curpage;
}
cur->h_flags = F_LEAF | F_CONT;
where = (char *) (&cur->h_linp[0]);
}
/* if we used pages from the free list, record changes to it */
if (*pgno == t->bt_free) {
t->bt_free = nextchn;
t->bt_flags &= ~BTF_METAOK;
}
return (RET_SUCCESS);
}
/*
* _BT_MARKCHAIN -- Mark a chain of pages as used by an internal node.
*
* Chains of indirect blocks pointed to by leaf nodes get reclaimed
* when the item that points to them gets deleted. Chains pointed
* to by internal nodes never get deleted. This routine marks a
* chain as pointed to by an internal node.
*
* Parameters:
* t -- tree in which to mark
* chain -- number of first page in chain
*
* Returns:
* RET_SUCCESS, RET_ERROR.
*
* Side Effects:
* None.
*/
int
_bt_markchain(t, chain)
BTREE_P t;
pgno_t chain;
{
pgno_t save;
save = t->bt_curpage->h_pgno;
if (_bt_getpage(t, chain) == RET_ERROR)
return (RET_ERROR);
t->bt_curpage->h_flags |= (F_DIRTY|F_PRESERVE);
if (_bt_getpage(t, save) == RET_ERROR)
return (RET_ERROR);
return (RET_SUCCESS);
}

View File

@ -1,752 +0,0 @@
/*-
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Olson.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)btree.c 5.9 (Berkeley) 5/7/91";
#endif /* LIBC_SCCS and not lint */
/*
* btree.c -- implementation of btree access method for 4.4BSD.
*
* The design here is based on that of the btree access method used
* in the Postgres database system at UC Berkeley. The implementation
* is wholly independent of the Postgres code.
*
* This implementation supports btrees on disk (supply a filename) or
* in memory (don't). Public interfaces defined here are:
*
* btree_open() -- wrapper; returns a filled DB struct for
* a btree.
*
* bt_open() -- open a new or existing btree.
* bt_get() -- fetch data from a tree by key.
* bt_seq() -- do a sequential scan on a tree.
* bt_put() -- add data to a tree by key.
* bt_delete() -- remove data from a tree by key.
* bt_close() -- close a btree.
* bt_sync() -- force btree pages to disk (disk trees only).
*/
#include <sys/param.h>
#include <sys/stat.h>
#include <signal.h>
#include <errno.h>
#include <fcntl.h>
#include <db.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "btree.h"
BTREEINFO _DefaultBTInfo = {
0, /* flags */
0, /* cachesize */
0, /* psize */
strcmp, /* compare */
0
};
/*
* BTREE_OPEN -- Wrapper routine to open a btree.
*
* Creates and fills a DB struct, and calls the routine that actually
* opens the btree.
*
* Parameters:
* f: filename to open
* flags: flag bits passed to open
* mode: permission bits, used if O_CREAT specified
* b: BTREEINFO pointer
*
* Returns:
* Filled-in DBT on success; NULL on failure, with errno
* set as appropriate.
*
* Side Effects:
* Allocates memory for the DB struct.
*/
DB *
btree_open(f, flags, mode, b)
const char *f;
int flags;
int mode;
const BTREEINFO *b;
{
DB *db;
BTREE t;
if ((db = (DB *) malloc((unsigned) sizeof(DB))) == (DB *) NULL)
return ((DB *) NULL);
if ((t = bt_open(f, flags, mode, b)) == (BTREE) NULL) {
(void) free ((char *) db);
return ((DB *) NULL);
}
db->internal = (char *) t;
db->close = bt_close;
db->del = bt_delete;
db->get = bt_get;
db->put = bt_put;
db->seq = bt_seq;
db->sync = bt_sync;
db->type = DB_BTREE;
return (db);
}
/*
* BT_OPEN -- Open a btree.
*
* This routine creates the correct kind (disk or in-memory) of
* btree and initializes it as required.
*
* Parameters:
* f -- name of btree (NULL for in-memory btrees)
* flags -- flags passed to open()
* mode -- mode passed to open ()
* b -- BTREEINFO structure, describing btree
*
* Returns:
* (Opaque) pointer to the btree. On failure, returns NULL
* with errno set as appropriate.
*
* Side Effects:
* Allocates memory, opens files.
*/
BTREE
bt_open(f, flags, mode, b)
char *f;
int flags;
int mode;
BTREEINFO *b;
{
BTREE_P t;
HTABLE ht;
int nbytes;
int fd;
CURSOR *c;
BTMETA m;
struct stat buf;
/* use the default info if none was provided */
if (b == (BTREEINFO *) NULL)
b = &_DefaultBTInfo;
if ((t = (BTREE_P) malloc((unsigned) sizeof *t)) == (BTREE_P) NULL)
return ((BTREE) NULL);
if (b->compare)
t->bt_compare = b->compare;
else
t->bt_compare = strcmp;
t->bt_fname = f;
t->bt_curpage = (BTHEADER *) NULL;
t->bt_free = P_NONE;
c = &(t->bt_cursor);
c->c_pgno = P_NONE;
c->c_index = 0;
c->c_flags = (u_char) NULL;
c->c_key = (char *) NULL;
t->bt_stack = (BTSTACK *) NULL;
t->bt_flags = 0;
/*
* If no file name was supplied, this is an in-memory btree.
* Otherwise, it's a disk-based btree.
*/
if (f == (char *) NULL) {
/* in memory */
if ((t->bt_psize = b->psize) < MINPSIZE) {
if (t->bt_psize != 0) {
(void) free ((char *) t);
errno = EINVAL;
return ((BTREE) NULL);
}
t->bt_psize = getpagesize();
}
nbytes = HTSIZE * sizeof(HTBUCKET *);
if ((ht = (HTABLE) malloc((unsigned) nbytes))
== (HTABLE) NULL) {
(void) free((char *) t);
return ((BTREE) NULL);
}
(void) bzero((char *) ht, nbytes);
t->bt_s.bt_ht = ht;
t->bt_npages = 0;
t->bt_lorder = BYTE_ORDER;
if (!(b->flags & R_DUP))
t->bt_flags |= BTF_NODUPS;
} else {
/* on disk */
if ((fd = open(f, O_RDONLY, 0)) < 0) {
/* doesn't exist yet, be sure page is big enough */
if ((t->bt_psize = b->psize) < sizeof(BTHEADER)
&& b->psize != 0) {
(void) free((char *) t);
errno = EINVAL;
return ((BTREE) NULL);
}
if (b->lorder == 0)
b->lorder = BYTE_ORDER;
if (b->lorder != BIG_ENDIAN
&& b->lorder != LITTLE_ENDIAN) {
(void) free((char *) t);
errno = EINVAL;
return ((BTREE) NULL);
}
t->bt_lorder = b->lorder;
if (!(b->flags & R_DUP))
t->bt_flags |= BTF_NODUPS;
} else {
/* exists, get page size from file */
if (read(fd, &m, sizeof(m)) < sizeof(m)) {
(void) close(fd);
(void) free((char *) t);
errno = EINVAL;
return ((BTREE) NULL);
}
/* lorder always stored in host-independent format */
NTOHL(m.m_lorder);
if (m.m_lorder != BIG_ENDIAN
&& m.m_lorder != LITTLE_ENDIAN) {
(void) free((char *) t);
errno = EINVAL;
return ((BTREE) NULL);
}
t->bt_lorder = m.m_lorder;
if (t->bt_lorder != BYTE_ORDER) {
BLSWAP(m.m_magic);
BLSWAP(m.m_version);
BLSWAP(m.m_psize);
BLSWAP(m.m_free);
BLSWAP(m.m_flags);
}
if (m.m_magic != BTREEMAGIC
|| m.m_version != BTREEVERSION
|| m.m_psize < MINPSIZE) {
(void) close(fd);
(void) free((char *) t);
#ifndef EFTYPE
#define EFTYPE -100
#endif
errno = EFTYPE;
return ((BTREE) NULL);
}
t->bt_psize = m.m_psize;
t->bt_free = m.m_free;
t->bt_flags |= (m.m_flags & BTF_NODUPS) | BTF_METAOK;
(void) close(fd);
}
/* now open the file the way the user wanted it */
if ((t->bt_s.bt_d.d_fd = open(f, flags, mode)) < 0) {
(void) free ((char *) t);
return ((BTREE) NULL);
}
/* access method files are always close-on-exec */
if (fcntl(t->bt_s.bt_d.d_fd, F_SETFL, 1) == -1) {
(void) close(t->bt_s.bt_d.d_fd);
(void) free ((char *) t);
return ((BTREE) NULL);
}
/* get number of pages, page size if necessary */
(void) fstat(t->bt_s.bt_d.d_fd, &buf);
if (t->bt_psize == 0)
t->bt_psize = buf.st_blksize;
t->bt_npages = (pgno_t) (buf.st_size / t->bt_psize);
/* page zero is metadata, doesn't count */
if (t->bt_npages > 0)
--(t->bt_npages);
if (b->cachesize == 0)
b->cachesize = DEFCACHE;
/* get an lru buffer cache, if the user asked for one */
if ((b->cachesize / t->bt_psize) > 0) {
BTDISK *d = &(t->bt_s.bt_d);
d->d_cache = lruinit(d->d_fd,
(int) (b->cachesize / t->bt_psize),
(int) t->bt_psize,
(char *) t->bt_lorder,
_bt_pgin, _bt_pgout);
if (d->d_cache == (char *) NULL) {
(void) free((char *) t);
return ((BTREE) NULL);
}
}
}
/* remember if tree was opened for write */
if (((flags & O_WRONLY) == O_WRONLY)
|| ((flags & O_RDWR) == O_RDWR))
t->bt_flags |= BTF_ISWRITE;
return ((BTREE) t);
}
/*
* BT_GET -- Get an entry from a btree.
*
* Does a key lookup in the tree to find the specified key, and returns
* the key/data pair found.
*
* Parameters:
* tree -- btree in which to do lookup
* key -- key to find
* data -- pointer to DBT in which to return data
* flag -- ignored
*
* Returns:
* RET_SUCCESS, RET_ERROR, or RET_SPECIAL if the key is not
* found. If key is not found, nothing is stored in the
* return DBT 'data'.
*
* Side Effects:
* None.
*
* Warnings:
* Return data is statically allocated, and will be overwritten
* at the next call.
*/
int
bt_get(dbp, key, data, flag)
DB *dbp;
DBT *key, *data;
u_long flag;
{
BTREE_P t = (BTREE_P) (dbp->internal);
BTHEADER *h;
DATUM *d;
BTITEM *item;
#ifdef lint
flag = flag;
#endif /* lint */
/* lookup */
item = _bt_search(t, key);
/* clear parent pointer stack */
while (_bt_pop(t) != P_NONE)
continue;
if (item == (BTITEM *) NULL)
return (RET_ERROR);
h = (BTHEADER *) t->bt_curpage;
data->size = 0;
data->data = (u_char *) NULL;
/* match? */
if (VALIDITEM(t, item)
&& _bt_cmp(t, key->data, item->bti_index) == 0) {
d = (DATUM *) GETDATUM(h, item->bti_index);
return (_bt_buildret(t, d, data, key));
}
/* nope */
return (RET_SPECIAL);
}
/*
* BT_PUT -- Add an entry to a btree.
*
* The specified (key, data) pair is added to the tree. If the tree
* was created for unique keys only, then duplicates will not be
* entered. If the requested key exists in the tree, it will be over-
* written unless the flags parameter is R_NOOVERWRITE, in which case
* the update will not be done. If duplicate keys are permitted in the
* tree, duplicates will be inserted and will not overwrite existing
* keys. Nodes are split as required.
*
* Parameters:
* tree -- btree in which to put the new entry
* key -- key component to add
* data -- data corresponding to key
* flag -- R_NOOVERWRITE or zero.
*
* Returns:
* RET_SUCCESS, RET_ERROR, or RET_SPECIAL if the
* NOOVERWRITE flag was set and the specified key exists
* in the database.
*
* Side Effects:
* None.
*/
int
bt_put(dbp, key, data, flag)
DB *dbp;
DBT *key, *data;
u_long flag;
{
BTREE_P t;
BTITEM *item;
t = (BTREE_P)dbp->internal;
/* look for this key in the tree */
item = _bt_search(t, key);
/*
* If this tree was originally created without R_DUP, then duplicate
* keys are not allowed. We need to check this at insertion time.
*/
if (VALIDITEM(t, item) && _bt_cmp(t, key->data, item->bti_index) == 0) {
if ((t->bt_flags & BTF_NODUPS) && flag == R_NOOVERWRITE) {
if (_bt_delone(t, item->bti_index) == RET_ERROR) {
while (_bt_pop(t) != P_NONE)
continue;
return (RET_ERROR);
}
}
}
return (_bt_insert(t, item, key, data, flag));
}
/*
* BT_DELETE -- delete a key from the tree.
*
* Deletes all keys (and their associated data items) matching the
* supplied key from the tree. If the flags entry is R_CURSOR, then
* the current item in the active scan is deleted.
*
* Parameters:
* tree -- btree from which to delete key
* key -- key to delete
* flags -- R_CURSOR or zero
*
* Returns:
* RET_SUCCESS, RET_ERROR, or RET_SPECIAL if the specified
* key was not in the tree.
*
* Side Effects:
* None.
*/
int
bt_delete(dbp, key, flags)
DB *dbp;
DBT *key;
u_long flags;
{
BTREE_P t;
BTHEADER *h;
BTITEM *item;
int ndel = 0;
t = (BTREE_P)dbp->internal;
if (flags == R_CURSOR)
return (_bt_crsrdel(t));
/* find the first matching key in the tree */
item = _bt_first(t, key);
h = t->bt_curpage;
/* don't need the descent stack for deletes */
while (_bt_pop(t) != P_NONE)
continue;
/* delete all matching keys */
for (;;) {
while (VALIDITEM(t, item)
&& (_bt_cmp(t, key->data, item->bti_index) == 0)) {
if (_bt_delone(t, item->bti_index) == RET_ERROR)
return (RET_ERROR);
ndel++;
}
if (VALIDITEM(t, item) || h->h_nextpg == P_NONE)
break;
/* next page, if necessary */
do {
if (_bt_getpage(t, h->h_nextpg) == RET_ERROR)
return (RET_ERROR);
h = t->bt_curpage;
} while (NEXTINDEX(h) == 0 && h->h_nextpg != P_NONE);
item->bti_pgno = h->h_pgno;
item->bti_index = 0;
if (!VALIDITEM(t, item)
|| _bt_cmp(t, key->data, item->bti_index) != 0)
break;
}
/* flush changes to disk */
if (ISDISK(t)) {
if (h->h_flags & F_DIRTY) {
if (_bt_write(t, t->bt_curpage, NORELEASE) == RET_ERROR)
return (RET_ERROR);
}
}
if (ndel == 0)
return (RET_SPECIAL);
return (RET_SUCCESS);
}
/*
* BT_SYNC -- sync the btree to disk.
*
* Parameters:
* tree -- btree to sync.
*
* Returns:
* RET_SUCCESS, RET_ERROR.
*/
bt_sync(dbp)
DB *dbp;
{
BTREE_P t;
BTHEADER *h;
pgno_t pgno;
t = (BTREE_P)dbp->internal;
/* if this is an in-memory btree, syncing is a no-op */
if (!ISDISK(t))
return (RET_SUCCESS);
h = (BTHEADER *) t->bt_curpage;
h->h_flags &= ~F_DIRTY;
if (ISCACHE(t)) {
pgno = t->bt_curpage->h_pgno;
if (_bt_write(t, h, RELEASE) == RET_ERROR)
return(RET_ERROR);
if (lrusync(t->bt_s.bt_d.d_cache) < RET_ERROR)
return (RET_ERROR);
if (_bt_getpage(t, pgno) == RET_ERROR)
return (RET_ERROR);
} else {
if (_bt_write(t, h, NORELEASE) == RET_ERROR)
return (RET_ERROR);
}
return (fsync(t->bt_s.bt_d.d_fd));
}
/*
* BT_SEQ -- Sequential scan interface.
*
* This routine supports sequential scans on the btree. If called with
* flags set to R_CURSOR, or if no seq scan has been initialized in the
* current tree, we initialize the scan. Otherwise, we advance the scan
* and return the next item.
*
* Scans can be either keyed or non-keyed. Keyed scans basically have
* a starting point somewhere in the middle of the tree. Non-keyed
* scans start at an endpoint. Also, scans can be backward (descending
* order), forward (ascending order), or no movement (keep returning
* the same item).
*
* Flags is checked every time we enter the routine, so the user can
* change directions on an active scan if desired. The key argument
* is examined only when we initialize the scan, in order to position
* it properly.
*
* Items are returned via the key and data arguments passed in.
*
* Parameters:
* tree -- btree in which to do scan
* key -- key, used to position scan on initialization, and
* used to return key components to the user.
* data -- used to return data components to the user.
* flags -- specify R_CURSOR, R_FIRST, R_LAST, R_NEXT, or
* R_PREV.
*
* Returns:
* RET_SUCCESS, RET_ERROR, or RET_SPECIAL if no more data
* exists in the tree in the specified direction.
*
* Side Effects:
* Changes the btree's notion of the current position in the
* scan.
*
* Warnings:
* The key and data items returned are static and will be
* overwritten by the next bt_get or bt_seq.
*/
int
bt_seq(dbp, key, data, flags)
DB *dbp;
DBT *key, *data;
u_long flags;
{
BTREE_P t;
BTHEADER *h;
DATUM *d;
int status;
t = (BTREE_P)dbp->internal;
/* do we need to initialize the scan? */
if (flags == R_CURSOR || flags == R_LAST || flags == R_FIRST
|| !(t->bt_flags & BTF_SEQINIT)) {
/* initialize it */
status = _bt_seqinit(t, key, flags);
} else {
/* just advance the current scan pointer */
status = _bt_seqadvance(t, flags);
}
key->size = data->size = 0;
key->data = data->data = (u_char *) NULL;
h = t->bt_curpage;
/* is there a valid item at the current scan location? */
if (status == RET_SPECIAL) {
if (flags == R_NEXT) {
if (t->bt_cursor.c_index >= NEXTINDEX(h)) {
if (NEXTINDEX(h) > 0)
t->bt_cursor.c_index = NEXTINDEX(h) - 1;
else
t->bt_cursor.c_index = 0;
}
} else {
t->bt_cursor.c_index = 0;
}
return (RET_SPECIAL);
} else if (status == RET_ERROR)
return (RET_ERROR);
/* okay, return the data */
d = (DATUM *) GETDATUM(h, t->bt_cursor.c_index);
return (_bt_buildret(t, d, data, key));
}
/*
* BT_CLOSE -- Close a btree
*
* Parameters:
* tree -- tree to close
*
* Returns:
* RET_SUCCESS, RET_ERROR.
*
* Side Effects:
* Frees space occupied by the tree.
*/
int
bt_close(dbp)
DB *dbp;
{
struct HTBUCKET *b, *sb;
BTREE_P t;
BTHEADER *h;
HTABLE ht;
int fd, i;
char *cache;
t = (BTREE_P)dbp->internal;
if (t->bt_cursor.c_key != (char *) NULL)
(void) free(t->bt_cursor.c_key);
if (!ISDISK(t)) {
/* in-memory tree, release hash table memory */
ht = t->bt_s.bt_ht;
for (i = 0; i < HTSIZE; i++) {
if ((b = ht[i]) == (struct HTBUCKET *) NULL)
break;
do {
sb = b;
(void) free((char *) b->ht_page);
b = b->ht_next;
(void) free((char *) sb);
} while (b != (struct HTBUCKET *) NULL);
}
(void) free ((char *) ht);
(void) free ((char *) t);
return (RET_SUCCESS);
}
if ((t->bt_flags & BTF_ISWRITE) && !(t->bt_flags & BTF_METAOK)) {
if (_bt_wrtmeta(t) == RET_ERROR)
return (RET_ERROR);
}
if (t->bt_curpage != (BTHEADER *) NULL) {
h = t->bt_curpage;
if (h->h_flags & F_DIRTY) {
if (_bt_write(t, h, RELEASE) == RET_ERROR)
return (RET_ERROR);
} else {
if (_bt_release(t, h) == RET_ERROR)
return (RET_ERROR);
}
/* flush and free the cache, if there is one */
if (ISCACHE(t)) {
cache = t->bt_s.bt_d.d_cache;
if (lrusync(cache) == RET_ERROR)
return (RET_ERROR);
lrufree(cache);
}
(void) free ((char *) h);
}
fd = t->bt_s.bt_d.d_fd;
(void) free ((char *) t);
return (close(fd));
}

View File

@ -1,201 +0,0 @@
/*-
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Olson.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)delete.c 5.2 (Berkeley) 2/22/91";
#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
#include <db.h>
#include <errno.h>
#include <string.h>
#include "btree.h"
/*
* _BT_CRSRDEL -- Delete the item pointed to by the cursor.
*
* This routine deletes the item most recently returned by a scan
* through the tree. Since it only makes sense to delete the current
* record once, we make sure that we don't try to delete twice without
* advancing the scan.
*
* Parameters:
* t -- tree in which to do deletion
*
* Returns:
* RET_SUCCESS, RET_ERROR.
*
* Side Effects:
* The call to _bt_delone marks the cursor, so we can tell that
* the current record has been deleted.
*/
int
_bt_crsrdel(t)
BTREE_P t;
{
CURSOR *c;
c = &(t->bt_cursor);
/* a cursor must exist, and can't have deleted the current key yet */
if (!(t->bt_flags & BTF_SEQINIT) || (c->c_flags & CRSR_BEFORE)) {
errno = EINVAL;
return (RET_ERROR);
}
if (_bt_getpage(t, c->c_pgno) == RET_ERROR)
return (RET_ERROR);
if (c->c_index >= NEXTINDEX(t->bt_curpage)) {
errno = EINVAL;
return (RET_ERROR);
}
return (_bt_delone(t, c->c_index));
}
/*
* _BT_DELONE -- Delete a single entry from a btree.
*
* This routine physically removes a btree entry from a leaf page.
* IDATUM items are *never* removed from internal nodes, regardless
* of whether the entries that originally caused them to be added
* are removed from the tree or not. In addition, pages made empty
* by element deletion are not actually reclaimed. They are,
* however, made available for reuse.
*
* To delete an item from a page, we pack the remaining items at
* the end of the page, overwriting the deleted item's entry. We
* move the line pointers backward on the page, overwriting the
* original item's line pointer. This guarantees that the space in
* the middle of the page is free -- a property that our insertion
* strategy relies on.
*
* This routine doesn't reclaim pages all of whose entries have
* been deleted. These pages are available for reuse, however.
* If an item is deleted that was too big to fit on a page, then
* the blocks that it occupies are put on a free list for reuse.
*
* Parameters:
* t -- btree from which to delete item
* index -- index of entry on current page to delete
*
* Returns:
* RET_SUCCESS, RET_ERROR.
*
* Side Effects:
* Physically changes page layout, adjusts internal page
* state to reflect the deletion of the item, and updates
* the list of free pages for this tree.
*/
int
_bt_delone(t, index)
BTREE_P t;
index_t index;
{
char *src, *dest;
int nbytes, nmoved;
index_t off;
index_t top;
index_t i;
pgno_t chain;
BTHEADER *h;
CURSOR *c;
DATUM *d;
/* deletion may confuse an active scan. fix it. */
c = &(t->bt_cursor);
if (t->bt_flags & BTF_SEQINIT && t->bt_curpage->h_pgno == c->c_pgno)
if (_bt_fixscan(t, index, (DATUM *) NULL, DELETE) == RET_ERROR)
return (RET_ERROR);
h = t->bt_curpage;
off = h->h_linp[index];
d = (DATUM *) GETDATUM(h, index);
/* if this is a big item, reclaim the space it occupies */
if (d->d_flags & D_BIGKEY) {
bcopy(&(d->d_bytes[0]),
(char *) &chain,
sizeof(chain));
if (_bt_delindir(t, chain) == RET_ERROR)
return (RET_ERROR);
h = t->bt_curpage;
d = (DATUM *) GETDATUM(h, index);
}
if (d->d_flags & D_BIGDATA) {
bcopy(&(d->d_bytes[d->d_ksize]),
(char *) &chain,
sizeof(chain));
if (_bt_delindir(t, chain) == RET_ERROR)
return (RET_ERROR);
h = t->bt_curpage;
d = (DATUM *) GETDATUM(h, index);
}
/* move the data down on the page */
nbytes = d->d_ksize + d->d_dsize
+ (sizeof(DATUM) - sizeof(char));
nbytes = LONGALIGN(nbytes);
src = ((char *) h) + h->h_upper;
dest = src + nbytes;
nmoved = (int) (((char *) d) - src);
(void) bcopy(src, dest, nmoved);
/* next move the line pointers up */
src = (char *) &(h->h_linp[index + 1]);
dest = (char *) &(h->h_linp[index]);
nmoved = (int) (((char *) &(h->h_linp[NEXTINDEX(h)])) - src);
(void) bcopy(src, dest, nmoved);
/* remember that we freed up some space */
h->h_upper += nbytes;
h->h_lower -= sizeof(index_t);
/* adjust offsets in line pointers affected by moving the data */
top = NEXTINDEX(h);
for (i = 0; i < top; i++) {
if (h->h_linp[i] < off)
h->h_linp[i] += nbytes;
}
/* it's gone */
h->h_flags |= F_DIRTY;
return (RET_SUCCESS);
}

View File

@ -1,312 +0,0 @@
/*-
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Olson.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)insert.c 5.3 (Berkeley) 2/22/91";
#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
#include <db.h>
#include <stdlib.h>
#include <string.h>
#include "btree.h"
/*
* _BT_INSERT -- Insert a new user datum in the btree.
*
* This routine is called by bt_put, the public interface, once the
* location for the new item is known. We do the work here, and
* handle splits if necessary.
*
* Parameters:
* t -- btree in which to do the insertion.
* item -- BTITEM describing location of new datum
* key -- key to insert
* data -- data associated with key
* flag -- magic cookie passed recursively to bt_put if we
* have to do a split
*
* Returns:
* RET_SUCCESS, RET_ERROR.
*/
int
_bt_insert(t, item, key, data, flag)
BTREE_P t;
BTITEM *item;
DBT *key;
DBT *data;
int flag;
{
index_t index;
BTHEADER *h;
DATUM *d;
int nbytes;
int status;
pgno_t pgno;
int keysize, datasize;
int bigkey, bigdata;
if (_bt_getpage(t, item->bti_pgno) == RET_ERROR)
return (RET_ERROR);
h = t->bt_curpage;
if (TOOBIG(t, data->size)) {
bigdata = TRUE;
datasize = sizeof(pgno_t);
} else {
bigdata = FALSE;
datasize = data->size;
}
if (TOOBIG(t, key->size)) {
bigkey = TRUE;
keysize = sizeof(pgno_t);
} else {
bigkey = FALSE;
keysize = key->size;
}
nbytes = keysize + datasize + (sizeof(DATUM) - sizeof(char));
nbytes = LONGALIGN(nbytes) + sizeof(index_t);
/* if there's not enough room here, split the page */
if ((h->h_upper - h->h_lower) < nbytes) {
if (_bt_split(t) == RET_ERROR)
return (RET_ERROR);
/* okay, try again (empty the stack first, though) */
while (_bt_pop((BTREE) t) != P_NONE)
continue;
return (bt_put((BTREE) t, key, data, flag));
}
/* put together a leaf page datum from the key/data pair */
index = item->bti_index;
nbytes = keysize + datasize + (sizeof(DATUM) - sizeof(char));
if ((d = (DATUM *) malloc((unsigned) nbytes)) == (DATUM *) NULL)
return (RET_ERROR);
d->d_ksize = keysize;
d->d_dsize = datasize;
d->d_flags = 0;
if (bigkey) {
if (_bt_indirect(t, key, &pgno) == RET_ERROR)
return (RET_ERROR);
(void) bcopy((char *) &pgno, &(d->d_bytes[0]), sizeof(pgno));
d->d_flags |= D_BIGKEY;
if (_bt_getpage(t, item->bti_pgno) == RET_ERROR)
return (RET_ERROR);
} else {
if (d->d_ksize > 0) {
(void) bcopy((char *) key->data,
(char *) &(d->d_bytes[0]),
(int) d->d_ksize);
}
}
if (bigdata) {
if (_bt_indirect(t, data, &pgno) == RET_ERROR)
return (RET_ERROR);
(void) bcopy((char *) &pgno,
&(d->d_bytes[keysize]),
sizeof(pgno));
d->d_flags |= D_BIGDATA;
if (_bt_getpage(t, item->bti_pgno) == RET_ERROR)
return (RET_ERROR);
} else {
if (d->d_dsize > 0) {
(void) bcopy((char *) data->data,
(char *) &(d->d_bytes[keysize]),
(int) d->d_dsize);
}
}
/* do the insertion */
status = _bt_insertat(t, (char *) d, index);
(void) free((char *) d);
return (status);
}
/*
* _BT_INSERTI -- Insert IDATUM on current page in the btree.
*
* This routine handles insertions to internal pages after splits
* lower in the tree. On entry, t->bt_curpage is the page to get
* the new IDATUM. We are also given pgno, the page number of the
* IDATUM that is immediately left of the new IDATUM's position.
* This guarantees that the IDATUM for the right half of the page
* after a split goes next to the IDATUM for its left half.
*
* Parameters:
* t -- tree in which to do insertion.
* id -- new IDATUM to insert
* pgno -- page number of IDATUM left of id's position
*
* Returns:
* RET_SUCCESS, RET_ERROR.
*/
int
_bt_inserti(t, id, pgno)
BTREE_P t;
IDATUM *id;
pgno_t pgno;
{
BTHEADER *h = t->bt_curpage;
index_t next, i;
IDATUM *idx;
char *key;
pgno_t chain;
int free_key;
int ignore;
if (id->i_flags & D_BIGKEY) {
free_key = TRUE;
bcopy(&(id->i_bytes[0]), (char *) &chain, sizeof(chain));
if (_bt_getbig(t, chain, &key, &ignore) == RET_ERROR)
return (RET_ERROR);
} else {
free_key = FALSE;
key = &(id->i_bytes[0]);
}
i = _bt_binsrch(t, key);
next = NEXTINDEX(h);
while (i < next && _bt_cmp(t, key, i) >= 0)
i++;
if (free_key)
(void) free(key);
/* okay, now we're close; find adjacent IDATUM */
for (;;) {
idx = (IDATUM *) GETDATUM(h,i);
if (idx->i_pgno == pgno) {
i++;
break;
}
--i;
}
/* correctly positioned, do the insertion */
return (_bt_insertat(t, (char *) id, i));
}
/*
* _BT_INSERTAT -- Insert a datum at a given location on the current page.
*
* This routine does insertions on both leaf and internal pages.
*
* Parameters:
* t -- tree in which to do insertion.
* p -- DATUM or IDATUM to insert.
* index -- index in line pointer array to put this item.
*
* Returns:
* RET_SUCCESS, RET_ERROR.
*
* Side Effects:
* Will rearrange line pointers to make space for the new
* entry. This means that any scans currently active are
* invalid after this.
*
* Warnings:
* There must be sufficient room for the new item on the page.
*/
int
_bt_insertat(t, p, index)
BTREE_P t;
char *p;
index_t index;
{
IDATUM *id = (IDATUM *) p;
DATUM *d = (DATUM *) p;
BTHEADER *h;
CURSOR *c;
index_t nxtindex;
char *src, *dest;
int nbytes;
/* insertion may confuse an active scan. fix it. */
c = &(t->bt_cursor);
if (t->bt_flags & BTF_SEQINIT && t->bt_curpage->h_pgno == c->c_pgno)
if (_bt_fixscan(t, index, d, INSERT) == RET_ERROR)
return (RET_ERROR);
h = t->bt_curpage;
nxtindex = (index_t) NEXTINDEX(h);
/*
* If we're inserting at the middle of the line pointer array,
* copy pointers that will follow the new one up on the page.
*/
if (index < nxtindex) {
src = (char *) &(h->h_linp[index]);
dest = (char *) &(h->h_linp[index + 1]);
nbytes = (h->h_lower - (src - ((char *) h)))
+ sizeof(h->h_linp[0]);
(void) bcopy(src, dest, nbytes);
}
/* compute size and copy data to page */
if (h->h_flags & F_LEAF) {
nbytes = d->d_ksize + d->d_dsize
+ (sizeof(DATUM) - sizeof(char));
} else {
nbytes = id->i_size + (sizeof(IDATUM) - sizeof(char));
}
dest = (((char *) h) + h->h_upper) - LONGALIGN(nbytes);
(void) bcopy((char *) p, dest, nbytes);
/* update statistics */
dest -= (int) h;
h->h_linp[index] = (index_t) dest;
h->h_upper = (index_t) dest;
h->h_lower += sizeof(index_t);
/* we're done */
h->h_flags |= F_DIRTY;
return (RET_SUCCESS);
}

View File

@ -1,528 +0,0 @@
/*-
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Olson.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)words.c 5.1 (Berkeley) 4/12/91";
#endif /* LIBC_SCCS and not lint */
/*
* test1.c -- simple btree test program.
*/
#include <stdio.h>
#include <ctype.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/file.h>
#include <db.h>
#include <btree.h>
#define DICTIONARY "/usr/share/dict/words"
typedef struct cmd_table {
char *cmd;
int nargs;
int (*func)();
char *descrip;
} cmd_table;
extern int cursor(), delcur(), delete(), first(), help(), insert();
extern int last(), lookup(), next(), previous();
cmd_table Commands[] = {
"cursor", 2, cursor,
"cursor <word>: point the scan cursor at <word>",
"delcur", 1, delcur,
"delcur: delete the word under the scan cursor",
"delete", 2, delete,
"delete <word>: delete <word> from the dictionary",
"first", 1, first,
"first: point the scan cursor at the first dictionary entry",
"help", 1, help,
"help: print this command summary",
"insert", 3, insert,
"insert <word> <def>: insert <word> into the dictionary with definition <def>",
"last", 1, last,
"last: point the scan cursor at the last dictionary entry",
"lookup", 2, lookup,
"lookup <word>: look up <word> in the dictionary",
"next", 1, next,
"next: move the scan cursor forward one word",
"previous", 1, previous,
"previous: move the scan cursor back one word",
(char *) NULL, 0, NULL, (char *) NULL,
};
char *Usage = "[-p pagesize] [-c cachesize] [-u] [-l|b|n] [dbname]";
main(argc, argv)
int argc;
char **argv;
{
char *dbname;
int c;
char *progname;
extern int strcmp();
extern char *optarg;
extern int optind;
DB *t;
BTREEINFO b;
progname = *argv;
b.psize = 0;
b.cachesize = 0;
b.lorder = 0;
b.flags = R_DUP;
b.compare = strcmp;
while ((c = getopt(argc, argv, "p:c:ulb")) != EOF) {
switch (c) {
case 'p':
b.psize = atoi(optarg);
break;
case 'c':
b.cachesize = atoi(optarg);
break;
case 'u':
b.flags = 0;
break;
case 'l':
b.lorder = LITTLE_ENDIAN;
break;
case 'b':
b.lorder = BIG_ENDIAN;
break;
default:
fprintf(stderr, "%s: usage: %s\n", progname, Usage);
exit (1);
}
}
if (argv[optind] != (char *) NULL)
dbname = argv[optind];
if ((t = btree_open(dbname, O_CREAT|O_RDWR, 0600, &b)) == (DB *) NULL) {
perror(progname);
exit (1);
}
load(t);
user(t);
}
load(t)
DB *t;
{
char *lbuf;
int i, l;
int status;
FILE *fp;
DBT key;
DBT data;
char word[64];
char drow[64];
printf("loading %s...\n", DICTIONARY);
fflush(stdout);
if ((fp = fopen(DICTIONARY, "r")) == (FILE *) NULL) {
perror("/usr/dict/words");
(void) (*(t->close))(t->internal);
exit (1);
}
key.data = &word[0];
data.data = &drow[0];
while ((lbuf = fgets(word, 64, fp)) != (char *) NULL) {
l = strlen(lbuf) - 1;
lbuf[l] = '\0';
for (i = 0; i < l; i++)
drow[l - (i + 1)] = word[i];
drow[l] = '\0';
key.size = data.size = l + 1;
status = (*(t->put))(t->internal, &key, &data, R_NOOVERWRITE);
switch (status) {
case RET_SUCCESS:
break;
case RET_ERROR:
perror("put");
break;
case RET_SPECIAL:
fprintf(stderr, "%s is a duplicate key!\n", lbuf);
fflush(stderr);
break;
}
}
(void) fclose(fp);
printf("done\n");
fflush(stdout);
}
user(t)
DB *t;
{
char *lbuf;
int argc;
int i;
char *argv[4];
char buf[512];
for (;;) {
printf("> ");
fflush(stdout);
if ((lbuf = fgets(&buf[0], 512, stdin)) == (char *) NULL)
break;
lbuf[strlen(lbuf) - 1] = '\0';
if (strcmp(lbuf, "quit") == 0)
break;
argc = parse(lbuf, &argv[0], 3);
if (argc == 0)
continue;
for (i = 0; Commands[i].cmd != (char *) NULL; i++) {
if (strcmp(Commands[i].cmd, argv[0]) == 0)
break;
}
if (Commands[i].cmd == (char *) NULL) {
fprintf(stderr,
"%s: command unknown ('help' for help)\n",
lbuf);
fflush(stderr);
continue;
}
if (Commands[i].nargs != argc) {
fprintf(stderr, "arg count\n");
fflush(stderr);
continue;
}
switch (argc) {
case 1:
(*(Commands[i].func))(t);
break;
case 2:
(*(Commands[i].func))(t, argv[1]);
break;
case 3:
(*(Commands[i].func))(t, argv[1], argv[2]);
break;
case 4:
(*(Commands[i].func))(t, argv[1], argv[2], argv[3]);
break;
}
}
(void) (*(t->close))(t->internal);
exit (0);
}
int
parse(lbuf, argv, maxargc)
char *lbuf;
char **argv;
int maxargc;
{
int argc = 0;
char *c;
c = lbuf;
while (isspace(*c))
c++;
while (*c != '\0' && argc < maxargc) {
*argv++ = c;
argc++;
while (!isspace(*c) && *c != '\0') {
c++;
}
while (isspace(*c))
*c++ = '\0';
}
return (argc);
}
int
cursor(t, arg)
DB *t;
char *arg;
{
int status;
DBT key;
DBT data;
key.data = arg;
key.size = strlen(arg + 1);
status = (*(t->seq))(t->internal, &key, &data, R_CURSOR);
if (status == RET_SUCCESS)
show(&key, &data);
else
perror("cursor");
}
int
delcur(t)
DB *t;
{
int status;
status = (*(t->delete))(t->internal, (DBT *) NULL, R_CURSOR);
if (status == RET_ERROR)
perror("delcur");
}
int
delete(t, arg)
DB *t;
char *arg;
{
int status;
DBT key;
key.data = arg;
key.size = strlen(arg) + 1;
status = (*(t->delete))(t->internal, &key, 0);
switch (status) {
case RET_SUCCESS:
break;
case RET_ERROR:
perror("delete");
break;
case RET_SPECIAL:
fprintf(stderr, "%s not found\n", arg);
fflush(stderr);
break;
}
}
int
first(t)
DB *t;
{
int status;
DBT key;
DBT data;
status = (*(t->seq))(t->internal, &key, &data, R_FIRST);
switch (status) {
case RET_ERROR:
perror("first");
break;
case RET_SPECIAL:
printf("no more keys");
break;
case RET_SUCCESS:
show(&key, &data);
break;
}
}
int
help(t)
DB *t;
{
int i;
#ifdef lint
t = t;
#endif /* lint */
for (i = 0; Commands[i].cmd != (char *) NULL; i++)
printf("%s\n", Commands[i].descrip);
printf("type 'quit' to quit\n");
}
int
insert(t, arg, def)
DB *t;
char *arg;
char *def;
{
int status;
DBT key;
DBT data;
key.data = arg;
key.size = strlen(arg) + 1;
data.data = def;
data.size = strlen(def) + 1;
status = (*(t->put))(t->internal, &key, &data, R_NOOVERWRITE);
switch (status) {
case RET_SUCCESS:
break;
case RET_ERROR:
perror("put");
break;
case RET_SPECIAL:
fprintf(stderr, "%s is a duplicate key!\n", arg);
fflush(stderr);
break;
}
}
int
last(t)
DB *t;
{
int status;
DBT key;
DBT data;
status = (*(t->seq))(t->internal, &key, &data, R_LAST);
switch (status) {
case RET_ERROR:
perror("last");
break;
case RET_SPECIAL:
printf("no more keys");
break;
case RET_SUCCESS:
show(&key, &data);
break;
}
}
int
lookup(t, arg)
DB *t;
char *arg;
{
int status;
DBT key;
DBT data;
key.data = arg;
key.size = strlen(arg) + 1;
status = (*(t->get))(t->internal, &key, &data, 0);
switch (status) {
case RET_SPECIAL:
printf("not found\n");
break;
case RET_SUCCESS:
show(&key, &data);
break;
case RET_ERROR:
perror("get");
break;
}
}
int
next(t)
DB *t;
{
int status;
DBT key;
DBT data;
status = (*(t->seq))(t->internal, &key, &data, R_NEXT);
switch (status) {
case RET_ERROR:
perror("next");
break;
case RET_SPECIAL:
printf("no more keys");
break;
case RET_SUCCESS:
show(&key, &data);
break;
}
}
int
previous(t)
DB *t;
{
int status;
DBT key;
DBT data;
status = (*(t->seq))(t->internal, &key, &data, R_PREV);
switch (status) {
case RET_ERROR:
perror("previous");
break;
case RET_SPECIAL:
printf("no more keys");
break;
case RET_SUCCESS:
show(&key, &data);
break;
}
}
show(key, data)
DBT *key;
DBT *data;
{
if (key->size > 0)
printf("%s", key->data);
if (data->size > 0)
printf("/%s", data->data);
printf("\n");
}

View File

@ -1,721 +0,0 @@
.\" Copyright (c) 1990 The Regents of the University of California.
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by the University of
.\" California, Berkeley and its contributors.
.\" 4. Neither the name of the University nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" @(#)db.3 5.16 (Berkeley) 4/2/91
.\"
.TH DB 3 "April 2, 1991"
.UC 7
.SH NAME
btree_open, hash_open, recno_open \- database access methods
.SH SYNOPSIS
.nf
.ft B
#include <sys/types.h>
#include <db.h>
DB *
btree_open(const char *file, int flags, int mode,
.ti +5
const BTREEINFO * openinfo);
DB *
hash_open(const char *file, int flags, int mode,
.ti +5
const HASHINFO * openinfo);
DB *
recno_open(const char *file, int flags, int mode,
.ti +5
const RECNOINFO * openinfo);
.ft R
.fi
.SH DESCRIPTION
.IR Btree_open ,
.IR hash_open ,
and
.I recno_open
are access method interfaces to database files in btree, hashed, and
flat-file formats, respectively.
The btree format is a representation of a sorted, balanced tree structure.
The hashed format is an extensible, dynamic hashing scheme.
The flat-file format is a UNIX file with fixed or variable length
lines.
These formats are described in more detail below.
.PP
Access to all file types is based on key/data pairs.
.PP
Each routine opens
.I file
for reading and/or writing.
Databases never intended to be preserved on disk may be created by setting
the file parameter to NULL.
The
.I flags
and
.I mode arguments
are as specified to the
.IR open (2)
routine, however, only the O_CREAT, O_EXCL, O_RDONLY, O_RDWR, O_TRUNC
and O_WRONLY flags are meaningful.
The argument
.I openinfo
is a pointer to an access method specific structure described below.
.PP
The open routines return a pointer to a DB structure on success and NULL
on error.
The DB structure contains at least the following fields:
.sp
.nf
typedef struct {
.RS
int (*close)(const DB *db);
int (*sync)(const DB *db);
int (*del)(const DB *db, const DBT *key, u_int flags);
int (*get)(const DB *db, DBT *key, DBT *data, u_int flags);
int (*put)(const DB *db, const DBT *key, const DBT *data,
.ti +5
u_int flags);
int (*seq)(const DB *db, DBT *key, DBT *data, u_int flags);
int type;
void *openinfo;
.RE
} DB;
.fi
.PP
The elements of this structure consist of a pointer to an access method
specific structure and a set of routines which perform various functions.
All of these routines take a pointer to a structure as returned by
one of the open routines, one or more pointers to key/data structures,
and, optionally, a flag value.
.TP
openinfo
A pointer to an internal structure specific to the access method.
.TP
type
The type of the underlying access method; either DB_BTREE, DB_HASH
or DB_RECNO.
.TP
close
A pointer to a routine to flush any cached information to disk, free any
allocated resources, and close the database file.
Since key/data pairs may be cached in memory, failing to close the
file with a
.I close
routine may result in inconsistent or lost information.
.I Close
routines return -1 on error (setting
.IR errno )
and 0 on success.
.TP
del
A pointer to a routine to remove key/data pairs from the database.
.I Delete
routines return -1 on error (setting
.IR errno ),
0 on success, and 1 if the specified
.I key
was not in the file.
.TP
get
A pointer to a routine which is the interface for keyed retrieval from
the database.
The address and length of the data associated with the specified
.I key
are returned in the structure referenced by
.IR data .
.I Get
routines return -1 on error (setting
.IR errno ),
0 on success, and 1 if the
.I key
was not in the file.
.TP
put
A pointer to a routine to store key/data pairs in the database.
.IP
The parameter
.I flag
must be set to one of the following values:
.RS
.TP
R_IAFTER
Append the data immediately after the data referenced by
.IR key ,
creating a new key/data pair.
(This implies that the access method is able to create new keys,
i.e. the keys are ordered and independent, for example, record numbers.
Applicable only to the
.B RECNO
access method.)
.TP
R_IBEFORE
Insert the data immediately before the data referenced by
.IR key ,
creating a new key/data pair.
(This implies that the access method is able to create new keys,
i.e. the keys are ordered and independent, for example, record numbers.
Applicable only to the
.B RECNO
access method.)
.TP
R_NOOVERWRITE
Enter the new key/data pair only if the key does not previously exist.
.TP
R_PUT
Enter the new key/data pair and replace any previously existing key.
.RE
.IP
.I Put
routines return -1 on error (setting
.IR errno ),
0 on success, and 1 if the R_NOOVERWRITE
.I flag
was set and the key already exists in the file.
.TP
seq
A pointer to a routine which is the interface for sequential
retrieval from the database.
The address and length of the key are returned in the structure
referenced by
.IR key ,
and the address and length of the data are returned in the
structure referenced
by
.IR data .
.IP
Sequential key/data pair retrieval may begin at any time, and the
position of the ``cursor'' is not affected by calls to the
.IR del ,
.IR get ,
.IR put ,
or
.I sync
routines.
Modifications to the database during a sequential scan will be reflected
in the scan, i.e. records inserted behind the cursor will not be returned
while records inserted in front of the cursor will be returned.
.IP
The flag value must be set to one of the following values:
.RS
.TP
R_CURSOR
The data associated with the specified key is returned.
This differs from the
.I get
routines in that it sets the ``cursor'' to the location of the
key as well.
(This implies that the access method has a implicit order which does
not change.
Applicable only to the
.B BTREE
and
.B RECNO
access methods.)
.TP
R_FIRST
The first key/data pair of the database is returned.
.TP
R_LAST
The last key/data pair of the database is returned.
(This implies that the access method has a implicit order which does
not change.
Applicable only to the
.B BTREE
and
.B RECNO
access methods.)
.TP
R_NEXT
Retrieve the key/data pair immediately after the key/data pair most recently
retrieved using the
.I seq
routine.
The cursor is moved to the returned key/data pair.
If
.I flag
is set to R_NEXT the first time the
.I seq
routine is called, the first key/data pair of the database is returned.
.TP
R_PREV
Retrieve the key/data pair immediately before the key/data pair most recently
retrieved using the
.I seq
routine.
The cursor is moved to the returned key/data pair.
If
.I flag
is set to R_PREV the first time the
.I seq
routine is called, the last key/data pair of the database is returned.
(This implies that the access method has a implicit order which does
not change.
Applicable only to the
.B BTREE
and
.B RECNO
access methods.)
.RE
.IP
.I Seq
routines return -1 on error (setting
.IR errno ),
0 on success, 1 if there are no more key/data pairs available.
If the
.B RECNO
access method is being used, and if the database file is a character special
file and no complete key/data pairs are currently available, the
.I seq
routines return 2.
.TP
sync
A pointer to a routine to flush any cached information to disk.
If the database is in memory only, the
.I sync
routine has no effect and will always succeed.
.I Sync
routines return -1 on error (setting
.IR errno )
and 0 on success.
.SH "KEY/DATA PAIRS"
Access to all file types is based on key/data pairs.
Both keys and data are represented by the following data structure:
.PP
typedef struct {
.RS
void *data;
.br
size_t size;
.RE
} DBT;
.PP
The elements of the DBT structure are defined as follows:
.TP
data
A pointer to a byte string.
.TP
size
The length of the byte string.
.PP
Key/data strings must fit into available memory.
.SH BTREE
One of the access methods is a btree: a sorted, balanced tree structure
with associated key/data pairs.
.PP
The access method specific data structure provided to
.I btree_open
is as follows:
.PP
typedef struct {
.RS
u_long flags;
.br
u_int psize;
.br
u_int cachesize;
.br
int (*compare)(const void *, const void *);
.br
int lorder;
.RE
} BTREEINFO;
.PP
The elements of this structure are defined as follows:
.TP
flags
The flag value is specified by
.IR or 'ing
any of the following values:
.RS
.TP
R_DUP
On insertion,
if the key to be inserted already exists,
permit insertion anyway.
This flag permits duplicate keys in the tree.
By default,
duplicates are not permitted,
and attempts to insert them will fail.
Note, the order of retrieval of key/data pairs with duplicate keys is
undefined.
.RE
.TP
cachesize
A suggested maximum size, in bytes, of the memory cache.
Setting this value to zero specifies that an appropriate amount of memory
should be used.
Since every search examines the root page of the tree, caching the most
recently used pages substantially improves access time.
In addition, physical writes are delayed as long as possible, so a moderate
cache can reduce the number of I/O operations significantly.
Obviously, using a cache increases the likelihood of corruption or lost data
if the system crashes while a tree is being modified.
However, caching 10
pages decreases the creation time of a large tree by between two and three
orders of magnitude.
.TP
compare
Compare is a user defined comparison function.
It must return an integer less than, equal to, or greater than zero if the
first argument is considered to be respectively less than, equal to, or
greater than the second.
The same comparison function must be used on a given tree every time it
is opened.
If no comparison function is specified,
.IR strcmp (3)
is used.
.TP
lorder
The byte order for 4-byte integers in the stored database metadata.
The number should represent the order as an integer; for example,
big endian order would be the number 4,321.
If
.I lorder
is 0 (no order is specified) the current host order is used.
If the file already exists, the specified value is ignored and the
value specified when the tree was created is used.
(Obviously, portability of the data forming the key/data pairs is the
concern of the application program.)
.TP
psize
Page size is the size in bytes of the pages used for nodes in the tree.
If the file already exists, the specified value is ignored and the
value specified when the tree was created is used.
If
.I psize
is zero, an appropriate page size is chosen (based on the system memory
and/or file system constraints), but will never be less than 512 bytes.
.PP
If the pointer to the
.I openinfo
data structure is NULL, the
.I btree_open
routine will use appropriate values.
.PP
If the database file already exists, and the O_TRUNC flag is not specified
to
.IR btree_open ,
the parameter
.I psize
ignored.
.PP
Key structures may reference byte strings of slightly less than one-half the
tree's page size only (see
.IR psize ).
Data structures may reference byte strings of essentially unlimited length.
.PP
Searches, insertions, and deletions in a btree will all complete in
O lg N.
.PP
Forward sequential scans of a tree are from the least key to the greatest.
.PP
Space freed up by deleting key/data pairs from a btree is never reclaimed,
although it is normally made available for reuse.
The exception to this is that space occupied by large data items (those
greater than one quarter the size of a page) is neither reclaimed nor reused.
This means that the btree storage structure is grow-only.
The only solutions are to avoid excessive deletions, or to create a fresh
tree periodically from a scan of an existing one.
.SH HASH
One of the access methods is hashed access and storage.
The access method specific data structure provided to
.I hash_open
is as follows:
.sp
typedef struct {
.RS
u_long (*hash)(const void *, const size_t);
.br
u_int cachesize;
.br
int bsize;
.br
int ffactor;
.br
int lorder;
.br
int nelem;
.RE
} HASHINFO;
.PP
The elements of this structure are defined as follows:
.TP
bsize
.I Bsize
defines the hash table bucket size, and is, by default, 256 bytes.
It may be preferable to increase the page size for disk-resident tables and
tables with large data items.
.TP
cachesize
A suggested maximum size, in bytes, of the memory cache.
Setting this value to zero specifies that an appropriate amount of memory
should be used.
.TP
ffactor
.I Ffactor
indicates a desired density within the hash table.
It is an approximation of the number of keys allowed to accumulate in any
one bucket, determining when the hash table grows or shrinks.
The default value is 8.
.TP
hash
.I Hash
is a user defined hash function.
Since no hash function performs equally well on all possible data, the
user may find that the built-in hash function does poorly on a particular
data set.
User specified hash functions must take two arguments (a pointer to a byte
string and a length) and return an u_long to be used as the hash value.
.TP
lorder
The byte order for 4-byte integers in the stored database metadata.
The number should represent the order as an integer; for example,
big endian order would be the number 4,321.
If
.I lorder
is 0 (no order is specified) the current host order is used.
If the file already exists, the specified value is ignored and the
value specified when the tree was created is used.
(Obviously, portability of the data forming the key/data pairs is the
concern of the application program.)
.TP
nelem
.I Nelem
is an estimate of the final size of the hash table.
If not set, the default value is 1.
If not set or set too low, hash tables will expand gracefully as keys
are entered, although a slight performance degradation may be noticed.
.PP
If the pointer to the
.I openinfo
data structure is NULL, the
.I hash_open
routine will use appropriate values.
.PP
If the hash table already exists, and the O_TRUNC flag is not
specified to
.IR hash_open ,
the parameters
.IR bsize ,
.IR ffactor ,
and
.I nelem
are ignored.
.PP
If a hash function is specified,
.I hash_open
will attempt to determine if the hash function specified is the same as
the one with which the database was created, and will fail if it is not.
.PP
Both key and data structures may reference byte strings of essentially
unlimited length.
.PP
Backward compatible interfaces to the routines described in
.IR dbm (3),
.IR hsearch (3),
and
.IR ndbm (3)
are provided, however, these interfaces are not compatible with
previous file formats.
.SH RECNO
One of the access methods is either variable or fixed-length records,
the former delimited by a specific byte value.
The access method specific data structure provided to
.I recno_open
is as follows:
.sp
typedef struct {
.RS
u_long flags;
.br
u_int cachesize;
.br
size_t reclen;
.br
u_char bval;
.RE
} RECNOINFO;
.PP
The elements of this structure are defined as follows:
.TP
flags
The flag value is specified by
.IR or 'ing
any of the following values:
.RS
.TP
R_FIXEDLEN
The records are fixed-length, not byte delimited.
The structure element
.I reclen
specifies the length of the record, and the structure element
.I bval
is used as the pad character.
.TP
R_SNAPSHOT
This flag requires that a snapshot of the file be taken when
.I recno_open
is called, instead of permitting any unmodified records to be
read from the original file.
.RE
.TP
cachesize
A suggested maximum size, in bytes, of the memory cache.
Setting this value to zero specifies that an appropriate amount of memory
should be used.
.TP
reclen
The length of a fixed-length record.
.TP
bval
The delimiting byte to be used to mark the end of a record for
variable-length records, and the pad character for fixed-length
records.
.PP
Variable-length and fixed-length data files require
.I key
structures to reference the following structure:
.sp
typedef struct {
.RS
u_long length;
.br
u_long number;
.br
u_long offset;
.br
u_char valid;
.RE
} RECNOKEY;
.PP
The elements of this structure are defined as follows:
.TP
length
The length of the record.
.TP
number
The record number.
.TP
offset
The offset in the file at which the record is located.
.TP
valid
A flag value which indicates the validity of the other fields in the
structure.
The flag value is specified by
.IR or 'ing
one or more of the following values:
.RS
.TP
R_LENGTH
The record length is valid.
.TP
R_NUMBER
The record number is valid.
.TP
R_OFFSET
The byte offset is valid.
.RE
.PP
If the record retrieval is successful, the record number, byte offset and
record length are set in the RECNOKEY structure referenced by the caller's
.I key
structure.
.PP
Data structures may reference byte strings of essentially unlimited length.
.SH ERRORS
The
.I open
routines may fail and set
.I errno
for any of the errors specified for the library routines
.IR open (2)
and
.IR malloc (3)
or the following:
.TP
[EFTYPE]
A file used by one of the
.I open
routines is incorrectly formatted.
.TP
[EINVAL]
A parameter has been specified (hash function, pad byte etc.) that is
incompatible with the current file specification or there is a mismatch
between the version number of file and the software.
.PP
The
.I close
routines may fail and set
.I errno
for any of the errors specified for the library routines
.IR close (2),
.IR read (2),
.IR write (2),
.IR free (3),
or
.IR fsync (2).
.PP
The
.IR del ,
.IR get ,
.I put
and
.I seq
routines may fail and set
.I errno
for any of the errors specified for the library routines
.IR read (2),
.IR write (2),
.IR free (3)
or
.IR malloc (3).
.PP
The
.I sync
routines may fail and set
.I errno
for any of the errors specified for the library routine
.IR fsync (2).
.SH "SEE ALSO"
.IR "Dynamic Hash Tables" ,
Per-Ake Larson, Communications of the ACM, April 1988.
.br
.IR "A New Hash Package for UNIX" ,
Margo Seltzer, USENIX Proceedings, Winter 1991.
.SH BUGS
The typedef DBT is a mnemonic for ``data base thang'', and was used
because noone could think of a reasonable name that wasn't already used.
.PP
None of the access methods provide any form of concurrent access,
locking, or transactions.
.PP
Only big and little endian byte order is supported.

View File

@ -1,672 +0,0 @@
/*-
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Margo Seltzer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)bigkey.c 5.5 (Berkeley) 3/12/91";
#endif /* LIBC_SCCS and not lint */
/******************************************************************************
PACKAGE: hash
DESCRIPTION:
Big key/data handling for the hashing package.
ROUTINES:
External
__big_keydata
__big_split
__big_insert
__big_return
__big_delete
__find_last_page
Internal
collect_key
collect_data
******************************************************************************/
/* Includes */
#include <sys/param.h>
#include <assert.h>
#include <errno.h>
#include <db.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "hash.h"
#include "page.h"
/* Externals */
/* buf.c */
extern BUFHEAD *__get_buf();
/* dynahash.c */
extern u_int call_hash();
/* page.c */
extern BUFHEAD *__add_ovflpage();
/* My externals */
extern int __big_keydata();
extern int __big_split();
extern int __big_insert();
extern int __big_return();
extern int __big_delete();
extern u_short __find_last_page();
extern int __find_bigpair();
/* My internals */
static int collect_key();
static int collect_data();
#ifdef HASH_STATISTICS
extern long hash_accesses, hash_collisions, hash_expansions, hash_overflows;
#endif
/*
Big_insert
You need to do an insert and the key/data pair is too big
0 ==> OK
-1 ==> ERROR
*/
extern int
__big_insert ( bufp, key, val )
BUFHEAD *bufp;
DBT *key, *val;
{
char *cp = bufp->page; /* Character pointer of p */
register u_short *p = (u_short *)cp;
char *key_data, *val_data;
int key_size, val_size;
int n;
u_short space, move_bytes, off;
key_data = (char *)key->data;
key_size = key->size;
val_data = (char *)val->data;
val_size = val->size;
/* First move the Key */
for ( space = FREESPACE(p) - BIGOVERHEAD;
key_size;
space = FREESPACE(p) - BIGOVERHEAD ) {
move_bytes = MIN(space, key_size);
off = OFFSET(p) - move_bytes;
bcopy (key_data, cp+off, move_bytes );
key_size -= move_bytes;
key_data += move_bytes;
n = p[0];
p[++n] = off;
p[0] = ++n;
FREESPACE(p) = off - PAGE_META(n);
OFFSET(p) = off;
p[n] = PARTIAL_KEY;
bufp = __add_ovflpage(bufp);
if ( !bufp ) {
return(-1);
}
n = p[0];
if ( !key_size ) {
if ( FREESPACE(p) ) {
move_bytes = MIN (FREESPACE(p), val_size);
off = OFFSET(p) - move_bytes;
p[n] = off;
bcopy ( val_data, cp + off, move_bytes );
val_data += move_bytes;
val_size -= move_bytes;
p[n-2] = FULL_KEY_DATA;
FREESPACE(p) = FREESPACE(p) - move_bytes;
OFFSET(p) = off;
}
else p[n-2] = FULL_KEY;
}
p = (u_short *)bufp->page;
cp = bufp->page;
bufp->flags |= BUF_MOD;
}
/* Now move the data */
for ( space = FREESPACE(p) - BIGOVERHEAD;
val_size;
space = FREESPACE(p) - BIGOVERHEAD ) {
move_bytes = MIN(space, val_size);
/*
Here's the hack to make sure that if the data ends
on the same page as the key ends, FREESPACE is
at least one
*/
if ( space == val_size && val_size == val->size ) {
move_bytes--;
}
off = OFFSET(p) - move_bytes;
bcopy (val_data, cp+off, move_bytes );
val_size -= move_bytes;
val_data += move_bytes;
n = p[0];
p[++n] = off;
p[0] = ++n;
FREESPACE(p) = off - PAGE_META(n);
OFFSET(p) = off;
if ( val_size ) {
p[n] = FULL_KEY;
bufp = __add_ovflpage (bufp);
if ( !bufp ) {
return(-1);
}
cp = bufp->page;
p = (u_short *)cp;
} else {
p[n] = FULL_KEY_DATA;
}
bufp->flags |= BUF_MOD;
}
return(0);
}
/*
Called when bufp's page contains a partial key (index should be 1)
All pages in the big key/data pair except bufp are freed. We cannot
free bufp because the page pointing to it is lost and we can't
get rid of its pointer.
Returns 0 => OK
-1 => ERROR
*/
extern int
__big_delete (bufp, ndx)
BUFHEAD *bufp;
int ndx;
{
register BUFHEAD *rbufp = bufp;
register BUFHEAD *last_bfp = NULL;
char *cp;
u_short *bp = (u_short *)bufp->page;
u_short *xbp;
u_short pageno = 0;
u_short off, free_sp;
int key_done = 0;
int n;
while (!key_done || (bp[2] != FULL_KEY_DATA)) {
if ( bp[2] == FULL_KEY || bp[2] == FULL_KEY_DATA ) key_done = 1;
/*
If there is freespace left on a FULL_KEY_DATA page,
then the data is short and fits entirely on this
page, and this is the last page.
*/
if ( bp[2] == FULL_KEY_DATA && FREESPACE(bp) ) break;
pageno = bp[bp[0]-1];
rbufp->flags |= BUF_MOD;
rbufp = __get_buf ( pageno, rbufp, 0 );
if ( last_bfp ) __free_ovflpage(last_bfp);
last_bfp = rbufp;
if ( !rbufp ) return(-1); /* Error */
bp = (u_short *)rbufp->page;
}
/*
If we get here then rbufp points to the last page of
the big key/data pair. Bufp points to the first
one -- it should now be empty pointing to the next
page after this pair. Can't free it because we don't
have the page pointing to it.
*/
/* This is information from the last page of the pair */
n = bp[0];
pageno = bp[n-1];
/* Now, bp is the first page of the pair */
bp = (u_short *)bufp->page;
if ( n > 2 ) {
/* There is an overflow page */
bp[1] = pageno;
bp[2] = OVFLPAGE;
bufp->ovfl = rbufp->ovfl;
} else {
/* This is the last page */
bufp->ovfl = NULL;
}
n -= 2;
bp[0] = n;
FREESPACE(bp) = hashp->BSIZE - PAGE_META(n);
OFFSET(bp) = hashp->BSIZE - 1;
bufp->flags |= BUF_MOD;
if ( rbufp ) __free_ovflpage(rbufp);
if ( last_bfp != rbufp ) __free_ovflpage(last_bfp);
hashp->NKEYS--;
return(0);
}
/*
0 = key not found
-1 = get next overflow page
-2 means key not found and this is big key/data
-3 error
*/
extern int
__find_bigpair(bufp, ndx, key, size )
BUFHEAD *bufp;
int ndx;
char *key;
int size;
{
register u_short *bp = (u_short *)bufp->page;
register char *p = bufp->page;
int ksize = size;
char *kkey = key;
u_short bytes;
for ( bytes = hashp->BSIZE - bp[ndx];
bytes <= size && bp[ndx+1] == PARTIAL_KEY;
bytes = hashp->BSIZE - bp[ndx] ) {
if ( bcmp ( p+bp[ndx], kkey, bytes ))return(-2);
kkey += bytes;
ksize -= bytes;
bufp = __get_buf ( bp[ndx+2], bufp, 0 );
if ( !bufp ) {
return(-3);
}
p = bufp->page;
bp = (u_short *)p;
ndx = 1;
}
if ( (bytes != ksize) || bcmp ( p+bp[ndx], kkey, bytes )) {
#ifdef HASH_STATISTICS
hash_collisions++;
#endif
return(-2);
}
else return (ndx);
}
/*
Given the buffer pointer of the first overflow page of a big pair,
find the end of the big pair
This will set bpp to the buffer header of the last page of the big pair.
It will return the pageno of the overflow page following the last page of
the pair; 0 if there isn't any (i.e. big pair is the last key in the
bucket)
*/
extern u_short
__find_last_page ( bpp )
BUFHEAD **bpp;
{
int n;
u_short pageno;
BUFHEAD *bufp = *bpp;
u_short *bp = (u_short *)bufp->page;
while ( 1 ) {
n = bp[0];
/*
This is the last page if:
the tag is FULL_KEY_DATA and either
only 2 entries
OVFLPAGE marker is explicit
there is freespace on the page
*/
if ( bp[2] == FULL_KEY_DATA &&
((n == 2) || (bp[n] == OVFLPAGE) || (FREESPACE(bp)) ) ) break;
pageno = bp[n-1];
bufp = __get_buf ( pageno, bufp, 0 );
if ( !bufp ) return (0); /* Need to indicate an error! */
bp = (u_short *)bufp->page;
}
*bpp = bufp;
if ( bp[0] > 2 ) return ( bp[3] );
else return(0);
}
/*
Return the data for the key/data pair
that begins on this page at this index
(index should always be 1)
*/
extern int
__big_return ( bufp, ndx, val, set_current )
BUFHEAD *bufp;
int ndx;
DBT *val;
int set_current;
{
BUFHEAD *save_p;
u_short save_addr;
u_short *bp = (u_short *)bufp->page;
u_short off, len;
char *cp, *tp;
while ( bp[ndx+1] == PARTIAL_KEY ) {
bufp = __get_buf ( bp[bp[0]-1], bufp, 0 );
if ( !bufp ) return(-1);
bp = (u_short *)bufp->page;
ndx = 1;
}
if ( bp[ndx+1] == FULL_KEY ) {
bufp = __get_buf ( bp[bp[0]-1], bufp, 0 );
if ( !bufp ) return(-1);
bp = (u_short *)bufp->page;
save_p = bufp;
save_addr = save_p->addr;
off = bp[1];
len = 0;
} else if (!FREESPACE(bp)) {
/*
This is a hack. We can't distinguish between
FULL_KEY_DATA that contains complete data or
incomplete data, so we require that if the
data is complete, there is at least 1 byte
of free space left.
*/
off = bp[bp[0]];
len = bp[1] - off;
save_p = bufp;
save_addr = bufp->addr;
bufp = __get_buf ( bp[bp[0]-1], bufp, 0 );
if ( !bufp ) return(-1);
bp = (u_short *)bufp->page;
} else {
/* The data is all on one page */
tp = (char *)bp;
off = bp[bp[0]];
val->data = (u_char *)tp + off;
val->size = bp[1] - off;
if ( set_current ) {
if ( bp[0] == 2 ) { /* No more buckets in chain */
hashp->cpage = NULL;
hashp->cbucket++;
hashp->cndx=1;
} else {
hashp->cpage = __get_buf ( bp[bp[0]-1], bufp, 0 );
if ( !hashp->cpage )return(-1);
hashp->cndx = 1;
if ( !((u_short *)hashp->cpage->page)[0] ) {
hashp->cbucket++;
hashp->cpage = NULL;
}
}
}
return(0);
}
val->size = collect_data ( bufp, len, set_current );
if ( val->size == -1 ) {
return(-1);
}
if ( save_p->addr != save_addr ) {
/* We are pretty short on buffers */
errno = EINVAL; /* OUT OF BUFFERS */
return(-1);
}
bcopy ( (save_p->page)+off, hashp->tmp_buf, len );
val->data = (u_char *)hashp->tmp_buf;
return(0);
}
/*
Count how big the total datasize is by
recursing through the pages. Then allocate
a buffer and copy the data as you recurse up.
*/
static int
collect_data ( bufp, len, set )
BUFHEAD *bufp;
int len;
int set;
{
register char *p = bufp->page;
register u_short *bp = (u_short *)p;
u_short save_addr;
int mylen, totlen;
BUFHEAD *xbp;
mylen = hashp->BSIZE - bp[1];
save_addr = bufp->addr;
if ( bp[2] == FULL_KEY_DATA ) { /* End of Data */
totlen = len + mylen;
if ( hashp->tmp_buf ) free (hashp->tmp_buf);
hashp->tmp_buf = (char *)malloc ( totlen );
if ( !hashp->tmp_buf ) {
return(-1);
}
if ( set ) {
hashp->cndx = 1;
if ( bp[0] == 2 ) { /* No more buckets in chain */
hashp->cpage = NULL;
hashp->cbucket++;
} else {
hashp->cpage = __get_buf ( bp[bp[0]-1], bufp, 0 );
if (!hashp->cpage) {
return(-1);
} else if ( !((u_short *)hashp->cpage->page)[0] ) {
hashp->cbucket++;
hashp->cpage = NULL;
}
}
}
} else {
xbp = __get_buf ( bp[bp[0]-1], bufp, 0 );
if ( !xbp || ((totlen = collect_data ( xbp, len + mylen, set )) < 1) ) {
return(-1);
}
}
if ( bufp->addr != save_addr ) {
errno = EINVAL; /* Out of buffers */
return(-1);
}
bcopy ( (bufp->page) + bp[1], &hashp->tmp_buf[len], mylen );
return ( totlen );
}
/*
Fill in the key and data
for this big pair
*/
extern int
__big_keydata ( bufp, ndx, key, val, set )
BUFHEAD *bufp;
int ndx;
DBT *key, *val;
int set;
{
key->size = collect_key ( bufp, 0, val, set );
if ( key->size == -1 ) {
return (-1);
}
key->data = (u_char *)hashp->tmp_key;
return(0);
}
/*
Count how big the total key size is by
recursing through the pages. Then collect
the data, allocate a buffer and copy the key as
you recurse up.
*/
static int
collect_key ( bufp, len, val, set )
BUFHEAD *bufp;
int len;
DBT *val;
int set;
{
char *p = bufp->page;
u_short *bp = (u_short *)p;
u_short save_addr;
int mylen, totlen;
BUFHEAD *xbp;
mylen = hashp->BSIZE - bp[1];
save_addr = bufp->addr;
totlen = len + mylen;
if ( bp[2] == FULL_KEY || bp[2] == FULL_KEY_DATA ) {/* End of Key */
if ( hashp->tmp_key ) free (hashp->tmp_key);
hashp->tmp_key = (char *)malloc ( totlen );
if ( !hashp->tmp_key ) {
return(-1);
}
__big_return ( bufp, 1, val, set );
} else {
xbp = __get_buf (bp[bp[0]-1], bufp, 0);
if ( !xbp || ((totlen = collect_key (xbp, totlen, val, set)) < 1 ) ) {
return(-1);
}
}
if ( bufp->addr != save_addr ) {
errno = EINVAL; /* MIS -- OUT OF BUFFERS */
return (-1);
}
bcopy ( (bufp->page) + bp[1], &hashp->tmp_key[len], mylen );
return ( totlen );
}
/*
return 0 => OK
-1 => error
*/
extern int
__big_split ( op, np, big_keyp, addr, obucket, ret )
BUFHEAD *op; /* Pointer to where to put keys that go in old bucket */
BUFHEAD *np; /* Pointer to new bucket page */
BUFHEAD *big_keyp; /* Pointer to first page containing the big key/data */
u_short addr; /* Address of big_keyp */
u_int obucket; /* Old Bucket */
SPLIT_RETURN *ret;
{
register u_short *prev_pagep;
register BUFHEAD *tmpp;
register u_short *tp;
BUFHEAD *bp = big_keyp;
u_short off, free_space;
u_short n;
DBT key, val;
u_int change;
/* Now figure out where the big key/data goes */
if (__big_keydata ( big_keyp, 1, &key, &val, 0 )) {
return(-1);
}
change = (__call_hash ( key.data, key.size ) != obucket );
if ( ret->next_addr = __find_last_page ( &big_keyp ) ) {
if (!(ret->nextp = __get_buf ( ret->next_addr, big_keyp, 0 ))) {
return(-1);;
}
} else {
ret->nextp = NULL;
}
/* Now make one of np/op point to the big key/data pair */
assert(np->ovfl == NULL);
if ( change ) tmpp = np;
else tmpp = op;
tmpp->flags |= BUF_MOD;
#ifdef DEBUG1
fprintf ( stderr, "BIG_SPLIT: %d->ovfl was %d is now %d\n", tmpp->addr,
(tmpp->ovfl?tmpp->ovfl->addr:0),
(bp?bp->addr:0) );
#endif
tmpp->ovfl = bp; /* one of op/np point to big_keyp */
tp = (u_short *)tmpp->page;
assert ( FREESPACE(tp) >= OVFLSIZE);
n = tp[0];
off = OFFSET(tp);
free_space = FREESPACE(tp);
tp[++n] = addr;
tp[++n] = OVFLPAGE;
tp[0] = n;
OFFSET(tp) = off;
FREESPACE(tp) = free_space - OVFLSIZE;
/*
Finally, set the new and old return values.
BIG_KEYP contains a pointer to the last page of the big key_data pair.
Make sure that big_keyp has no following page (2 elements) or create
an empty following page.
*/
ret->newp = np;
ret->oldp = op;
tp = (u_short *)big_keyp->page;
big_keyp->flags |= BUF_MOD;
if ( tp[0] > 2 ) {
/*
There may be either one or two offsets on this page
If there is one, then the overflow page is linked on
normally and tp[4] is OVFLPAGE. If there are two, tp[4]
contains the second offset and needs to get stuffed in
after the next overflow page is added
*/
n = tp[4];
free_space = FREESPACE(tp);
off = OFFSET(tp);
tp[0] -= 2;
FREESPACE(tp) = free_space + OVFLSIZE;
OFFSET(tp) = off;
tmpp = __add_ovflpage ( big_keyp );
if ( !tmpp ) {
return(-1);
}
tp[4] = n;
} else {
tmpp = big_keyp;
}
if ( change ) ret->newp = tmpp;
else ret->oldp = tmpp;
return(0);
}

View File

@ -1,346 +0,0 @@
/*-
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Margo Seltzer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)buf.c 5.7 (Berkeley) 3/12/91";
#endif /* LIBC_SCCS and not lint */
/******************************************************************************
PACKAGE: hash
DESCRIPTION:
Contains buffer management
ROUTINES:
External
__buf_init
__get_buf
__buf_free
__reclaim_buf
Internal
newbuf
******************************************************************************/
#include <sys/param.h>
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include "hash.h"
/* Externals */
extern HTAB *hashp;
/* My internals */
static BUFHEAD *newbuf();
/* Unlink B from its place in the lru */
#define BUF_REMOVE(B) \
{ \
B->prev->next = B->next; \
B->next->prev = B->prev; \
}
/* Insert B after P */
#define BUF_INSERT(B,P) \
{ \
B->next = P->next; \
B->prev = P; \
P->next = B; \
B->next->prev = B; \
}
#define MRU hashp->bufhead.next
#define LRU hashp->bufhead.prev
#define MRU_INSERT(B) BUF_INSERT(B,(&hashp->bufhead))
#define LRU_INSERT(B) BUF_INSERT(B,LRU)
/*
We are looking for a buffer with address "addr".
If prev_bp is NULL, then address is a bucket index.
If prev_bp is not NULL, then it points to the page previous
to an overflow page that we are trying to find.
CAVEAT: The buffer header accessed via prev_bp's ovfl field
may no longer be valid. Therefore, you must always verify that
its address matches the address you are seeking.
*/
extern BUFHEAD *
__get_buf ( addr, prev_bp, newpage )
u_int addr;
BUFHEAD *prev_bp;
int newpage; /* If prev_bp is set, indicates that this is
a new overflow page */
{
register int segment_ndx;
register BUFHEAD *bp;
register unsigned is_disk = 0;
register unsigned is_disk_mask = 0;
SEGMENT segp;
if ( prev_bp ) {
bp = prev_bp->ovfl;
if ( !bp || (bp->addr != addr) ) bp = NULL;
if ( !newpage ) is_disk = BUF_DISK;
}
else {
/* Grab buffer out of directory */
segment_ndx = addr & ( hashp->SGSIZE - 1 );
/*
* valid segment ensured by __call_hash()
*/
segp = hashp->dir[addr >> hashp->SSHIFT];
#ifdef DEBUG
assert(segp != NULL);
#endif
bp = PTROF(segp[segment_ndx]);
is_disk_mask = ISDISK(segp[segment_ndx]);
is_disk = is_disk_mask || !hashp->new_file;
}
if ( !bp ) {
bp = newbuf ( addr, prev_bp );
if ( !bp || __get_page ( bp->page, addr, !prev_bp, is_disk, 0 )) {
return(NULL);
}
if ( !prev_bp ) {
segp[segment_ndx] = (BUFHEAD *)((unsigned)bp | is_disk_mask );
}
} else {
BUF_REMOVE ( bp );
MRU_INSERT ( bp );
}
return(bp);
}
/*
We need a buffer for this page. Either allocate one, or
evict a resident one (if we have as many buffers as we're
allowed) and put this one in.
If newbuf finds an error (returning NULL), it also sets errno
*/
static BUFHEAD *
newbuf ( addr, prev_bp )
u_int addr;
BUFHEAD *prev_bp;
{
register BUFHEAD *bp; /* The buffer we're going to use */
register BUFHEAD *xbp; /* Temp pointer */
register BUFHEAD *next_xbp;
int segment_ndx;
u_short *shortp;
u_short oaddr;
SEGMENT segp;
oaddr = 0;
bp = LRU;
/*
If LRU buffer is pinned, the buffer pool is too small.
We need to allocate more buffers
*/
if ( hashp->nbufs || (bp->flags & BUF_PIN) ) {
/* Allocate a new one */
bp = (BUFHEAD *)malloc ( sizeof (struct _bufhead) );
if ( !bp || !(bp->page = (char *)malloc ( hashp->BSIZE )) ) {
return (NULL);
}
hashp->nbufs--;
} else {
/* Kick someone out */
BUF_REMOVE( bp );
/*
If this is an overflow page with addr 0, it's already
been flushed back in an overflow chain and initialized
*/
if ( (bp->addr != 0) || (bp->flags & BUF_BUCKET) ) {
/*
Set oaddr before __put_page so that you get it
before bytes are swapped
*/
shortp = (u_short *)bp->page;
if ( shortp[0] ) {
oaddr = shortp[shortp[0]-1];
}
if ( (bp->flags & BUF_MOD) &&
__put_page(bp->page, bp->addr, (int)IS_BUCKET(bp->flags), 0) ) {
return(NULL);
}
/*
Update the pointer to this page (i.e. invalidate it).
If this is a new file (i.e. we created it at open time),
make sure that we mark pages which have been written to
disk so we retrieve them from disk later, rather than
allocating new pages.
*/
if ( IS_BUCKET(bp->flags)) {
segment_ndx = bp->addr & ( hashp->SGSIZE - 1 );
segp = hashp->dir[bp->addr >> hashp->SSHIFT];
assert(segp != NULL);
if ( hashp->new_file &&
((bp->flags & BUF_MOD) || ISDISK(segp[segment_ndx])) ) {
segp[segment_ndx] = (BUFHEAD *)BUF_DISK;
} else segp[segment_ndx] = NULL;
}
/*
Since overflow pages can only be access by means of
their bucket, free overflow pages associated with this
bucket.
*/
for ( xbp = bp; xbp->ovfl; ) {
next_xbp = xbp->ovfl;
xbp->ovfl = 0;
xbp = next_xbp;
/* Check that ovfl pointer is up date */
if ( IS_BUCKET(xbp->flags) || (oaddr != xbp->addr) ) break;
shortp = (u_short *)xbp->page;
if ( shortp[0] ) {
oaddr = shortp[shortp[0]-1]; /* set before __put_page */
}
if ( (xbp->flags & BUF_MOD) &&
__put_page ( xbp->page, xbp->addr, 0, 0 ) ) {
return(NULL);
}
xbp->addr = 0;
xbp->flags = 0;
BUF_REMOVE ( xbp );
LRU_INSERT ( xbp );
}
}
}
/* Now assign this buffer */
bp->addr = addr;
#ifdef DEBUG1
fprintf ( stderr, "NEWBUF1: %d->ovfl was %d is now %d\n", bp->addr,
(bp->ovfl?bp->ovfl->addr:0), 0);
#endif
bp->ovfl = NULL;
if ( prev_bp ) {
/*
If prev_bp is set, this is an overflow page, hook it in to the
buffer overflow links
*/
#ifdef DEBUG1
fprintf ( stderr, "NEWBUF2: %d->ovfl was %d is now %d\n", prev_bp->addr,
(prev_bp->ovfl?bp->ovfl->addr:0),
(bp?bp->addr: 0));
#endif
prev_bp->ovfl = bp;
bp->flags = 0;
} else bp->flags = BUF_BUCKET;
MRU_INSERT ( bp );
return ( bp );
}
extern void
__buf_init ( nbytes )
int nbytes;
{
int npages;
BUFHEAD *bfp = &(hashp->bufhead);
npages = (nbytes + hashp->BSIZE - 1) >> hashp->BSHIFT;
npages = MAX ( npages, MIN_BUFFERS );
hashp->nbufs = npages;
bfp->next = bfp;
bfp->prev = bfp;
/*
This space is calloc'd so these are already null
bfp->ovfl = NULL;
bfp->flags = 0;
bfp->page = NULL;
bfp->addr = 0;
*/
}
extern int
__buf_free ( do_free, to_disk )
int do_free;
int to_disk;
{
BUFHEAD *bp;
/* Need to make sure that buffer manager has been initialized */
if ( !LRU ) {
return(0);
}
for ( bp = LRU; bp != &hashp->bufhead; ) {
/* Check that the buffer is valid */
if ( bp->addr || IS_BUCKET(bp->flags) ) {
if ( to_disk && (bp->flags & BUF_MOD) &&
__put_page (bp->page, bp->addr, IS_BUCKET(bp->flags), 0 )) {
return (-1);
}
}
/* Check if we are freeing stuff */
if ( do_free ) {
if ( bp->page ) free ( bp->page );
BUF_REMOVE(bp);
(void)free ( bp );
bp = LRU;
} else bp = bp->prev;
}
return(0);
}
extern void
__reclaim_buf ( bp )
BUFHEAD *bp;
{
bp->ovfl = 0;
bp->addr = 0;
bp->flags = 0;
BUF_REMOVE ( bp );
LRU_INSERT ( bp );
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,104 +0,0 @@
/*-
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Margo Seltzer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
char copyright[] =
"@(#) Copyright (c) 1990 The Regents of the University of California.\n\
All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)tcreat3.c 5.1 (Berkeley) 1/31/91";
#endif /* not lint */
#include <sys/types.h>
#include <stdio.h>
#include <sys/file.h>
#include <db.h>
#define INITIAL 25000
#define MAXWORDS 25000 /* # of elements in search table */
char wp1[8192];
char wp2[8192];
main(argc, argv)
char **argv;
{
DBT item, key;
DB *dbp;
HASHINFO ctl;
FILE *fp;
int trash;
int i = 0;
argv++;
ctl.hash = NULL;
ctl.bsize = atoi(*argv++);
ctl.ffactor = atoi(*argv++);
ctl.nelem = atoi(*argv++);
ctl.lorder = 0;
if (!(dbp = hash_open( "hashtest", O_CREAT|O_TRUNC|O_RDWR, 0600, &ctl))){
/* create table */
fprintf(stderr, "cannot create: hash table (size %d)\n",
INITIAL);
exit(1);
}
key.data = wp1;
item.data = wp2;
while ( fgets(wp1, 8192, stdin) &&
fgets(wp2, 8192, stdin) &&
i++ < MAXWORDS) {
/*
* put info in structure, and structure in the item
*/
key.size = strlen(wp1);
item.size = strlen(wp2);
/*
* enter key/data pair into the table
*/
if ((dbp->put)(dbp, &key, &item, R_NOOVERWRITE) != NULL) {
fprintf(stderr, "cannot enter: key %s\n",
item.data);
exit(1);
}
}
(dbp->close)(dbp);
exit(0);
}

View File

@ -1,122 +0,0 @@
/*-
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Margo Seltzer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
char copyright[] =
"@(#) Copyright (c) 1990 The Regents of the University of California.\n\
All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)tdel.c 5.2 (Berkeley) 3/12/91";
#endif /* not lint */
#include <sys/types.h>
#include <sys/file.h>
#include <db.h>
#include <stdio.h>
#define INITIAL 25000
#define MAXWORDS 25000 /* # of elements in search table */
/* Usage: thash pagesize fillfactor file */
char wp1[8192];
char wp2[8192];
main(argc, argv)
char **argv;
{
DBT item, key;
DB *dbp;
HASHINFO ctl;
FILE *fp;
int stat;
int i = 0;
argv++;
ctl.nelem = INITIAL;
ctl.hash = NULL;
ctl.bsize = atoi(*argv++);
ctl.ffactor = atoi(*argv++);
ctl.cachesize = 1024 * 1024; /* 1 MEG */
ctl.lorder = 0;
argc -= 2;
if (!(dbp = hash_open( NULL, O_CREAT|O_RDWR, 0400, &ctl))) {
/* create table */
fprintf(stderr, "cannot create: hash table size %d)\n",
INITIAL);
exit(1);
}
key.data = wp1;
item.data = wp2;
while ( fgets(wp1, 8192, stdin) &&
fgets(wp2, 8192, stdin) &&
i++ < MAXWORDS) {
/*
* put info in structure, and structure in the item
*/
key.size = strlen(wp1);
item.size = strlen(wp2);
/*
* enter key/data pair into the table
*/
if ((dbp->put)(dbp, &key, &item, R_NOOVERWRITE) != NULL) {
fprintf(stderr, "cannot enter: key %s\n",
item.data);
exit(1);
}
}
if ( --argc ) {
fp = fopen ( argv[0], "r");
i = 0;
while ( fgets(wp1, 8192, fp) &&
fgets(wp2, 8192, fp) &&
i++ < MAXWORDS) {
key.size = strlen(wp1);
stat = (dbp->delete)(dbp, &key);
if (stat) {
fprintf ( stderr, "Error retrieving %s\n", key.data );
exit(1);
}
}
fclose(fp);
}
(dbp->close)(dbp);
exit(0);
}

View File

@ -1,132 +0,0 @@
/*-
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Margo Seltzer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
char copyright[] =
"@(#) Copyright (c) 1990 The Regents of the University of California.\n\
All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)thash4.c 5.2 (Berkeley) 3/12/91";
#endif /* not lint */
#include <stdio.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/timeb.h>
#include <errno.h>
#include <db.h>
#define INITIAL 25000
#define MAXWORDS 25000 /* # of elements in search table */
/* Usage: thash pagesize fillfactor file */
char wp1[256];
char wp2[8192];
main(argc, argv)
char **argv;
{
DBT item, key, res;
DB *dbp;
HASHINFO ctl;
FILE *fp;
int stat;
time_t t;
int i = 0;
argv++;
ctl.hash = NULL;
ctl.bsize = atoi(*argv++);
ctl.ffactor = atoi(*argv++);
ctl.nelem = atoi(*argv++);
ctl.cachesize = atoi(*argv++);
ctl.lorder = 0;
if (!(dbp = hash_open( NULL, O_CREAT|O_RDWR, 0400, &ctl))) {
/* create table */
fprintf(stderr, "cannot create: hash table size %d)\n",
INITIAL);
fprintf(stderr, "\terrno: %d\n", errno);
exit(1);
}
key.data = wp1;
item.data = wp2;
while ( fgets(wp1, 256, stdin) &&
fgets(wp2, 8192, stdin) &&
i++ < MAXWORDS) {
/*
* put info in structure, and structure in the item
*/
key.size = strlen(wp1);
item.size = strlen(wp2);
/*
* enter key/data pair into the table
*/
if ((dbp->put)(dbp, &key, &item, R_NOOVERWRITE) != NULL) {
fprintf(stderr, "cannot enter: key %s\n",
item.data);
fprintf(stderr, "\terrno: %d\n", errno);
exit(1);
}
}
if ( --argc ) {
fp = fopen ( argv[0], "r");
i = 0;
while ( fgets(wp1, 256, fp) &&
fgets(wp2, 8192, fp) &&
i++ < MAXWORDS) {
key.size = strlen(wp1);
stat = (dbp->get)(dbp, &key, &res);
if (stat < 0 ) {
fprintf ( stderr, "Error retrieving %s\n", key.data );
fprintf(stderr, "\terrno: %d\n", errno);
exit(1);
} else if ( stat > 0 ) {
fprintf ( stderr, "%s not found\n", key.data );
fprintf(stderr, "\terrno: %d\n", errno);
exit(1);
}
}
fclose(fp);
}
dbp->close(dbp);
exit(0);
}

View File

@ -1,105 +0,0 @@
/*-
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Margo Seltzer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
char copyright[] =
"@(#) Copyright (c) 1990 The Regents of the University of California.\n\
All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)tread2.c 5.2 (Berkeley) 3/12/91";
#endif /* not lint */
#include <sys/types.h>
#include <stdio.h>
#include <sys/file.h>
#include <db.h>
#define INITIAL 25000
#define MAXWORDS 25000 /* # of elements in search table */
typedef struct { /* info to be stored */
int num, siz;
} info;
char wp1[256];
char wp2[256];
main(argc, argv)
char **argv;
{
DBT item, key, res;
DB *dbp;
HASHINFO ctl;
int stat;
int i = 0;
ctl.nelem = INITIAL;
ctl.hash = NULL;
ctl.bsize = 64;
ctl.ffactor = 1;
ctl.cachesize = atoi(*argv++);
ctl.lorder = 0;
if (!(dbp = hash_open( "hashtest", O_RDONLY, 0400, &ctl))) {
/* create table */
fprintf(stderr, "cannot open: hash table\n" );
exit(1);
}
key.data = wp1;
item.data = wp2;
while ( fgets(wp1, 256, stdin) &&
fgets(wp2, 256, stdin) &&
i++ < MAXWORDS) {
/*
* put info in structure, and structure in the item
*/
key.size = strlen(wp1);
item.size = strlen(wp2);
stat = (dbp->get)(dbp, &key, &res);
if (stat < 0) {
fprintf ( stderr, "Error retrieving %s\n", key.data );
exit(1);
} else if ( stat > 0 ) {
fprintf ( stderr, "%s not found\n", key.data );
exit(1);
}
}
(dbp->close)(dbp);
exit(0);
}

View File

@ -1,88 +0,0 @@
/*-
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Margo Seltzer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
char copyright[] =
"@(#) Copyright (c) 1990 The Regents of the University of California.\n\
All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)tseq.c 5.1 (Berkeley) 1/31/91";
#endif /* not lint */
#include <sys/types.h>
#include <stdio.h>
#include <sys/file.h>
#include <db.h>
#define INITIAL 25000
#define MAXWORDS 25000 /* # of elements in search table */
char wp[8192];
char cp[8192];
main(argc, argv)
char **argv;
{
DBT item, key, res;
DB *dbp;
FILE *fp;
int stat;
if (!(dbp = hash_open( "hashtest", O_RDONLY, 0400, NULL))) {
/* create table */
fprintf(stderr, "cannot open: hash table\n" );
exit(1);
}
/*
* put info in structure, and structure in the item
*/
for ( stat = (dbp->seq) (dbp, &res, &item, 1 );
stat == 0;
stat = (dbp->seq) (dbp, &res, &item, 0 ) ) {
bcopy ( res.data, wp, res.size );
wp[res.size] = 0;
bcopy ( item.data, cp, item.size );
cp[item.size] = 0;
printf ( "%s %s\n", wp, cp );
}
(dbp->close)(dbp);
exit(0);
}

View File

@ -1,107 +0,0 @@
/*-
* Copyright (c) 1990 The Regents of the University of California.
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Margo Seltzer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
char copyright[] =
"@(#) Copyright (c) 1990 The Regents of the University of California.\n\
All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)tverify.c 5.2 (Berkeley) 3/12/91";
#endif /* not lint */
#include <sys/types.h>
#include <stdio.h>
#include <sys/file.h>
#include <db.h>
#define INITIAL 25000
#define MAXWORDS 25000 /* # of elements in search table */
typedef struct { /* info to be stored */
int num, siz;
} info;
char wp1[8192];
char wp2[8192];
main(argc, argv)
char **argv;
{
DBT key, res;
DB *dbp;
HASHINFO ctl;
int trash;
int stat;
int i = 0;
ctl.nelem = INITIAL;
ctl.hash = NULL;
ctl.bsize = 64;
ctl.ffactor = 1;
ctl.cachesize = 1024 * 1024; /* 1 MEG */
ctl.lorder = 0;
if (!(dbp = hash_open( "hashtest", O_RDONLY, 0400, &ctl))) {
/* create table */
fprintf(stderr, "cannot open: hash table\n" );
exit(1);
}
key.data = wp1;
while ( fgets(wp1, 8192, stdin) &&
fgets(wp2, 8192, stdin) &&
i++ < MAXWORDS) {
/*
* put info in structure, and structure in the item
*/
key.size = strlen(wp1);
stat = (dbp->get)(dbp, &key, &res);
if (stat < 0) {
fprintf ( stderr, "Error retrieving %s\n", key.data );
exit(1);
} else if ( stat > 0 ) {
fprintf ( stderr, "%s not found\n", key.data );
exit(1);
}
if ( memcmp ( res.data, wp2, res.size ) ) {
fprintf ( stderr, "data for %s is incorrect. Data was %s. Should have been %s\n", key.data, res.data, wp2 );
}
}
(dbp->close)(dbp);
exit(0);
}