Clean up deleted files.
This commit is contained in:
parent
68028dc2de
commit
6609149bb3
|
@ -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);
|
||||
}
|
|
@ -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));
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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");
|
||||
}
|
721
lib/libc/db/db.3
721
lib/libc/db/db.3
|
@ -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.
|
|
@ -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);
|
||||
}
|
|
@ -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
12209
lib/libc/db/hash/hash.ps
12209
lib/libc/db/hash/hash.ps
File diff suppressed because it is too large
Load Diff
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue