author Mark Spencer Sat, 4 Jan 2003 18:53:14 +0000 (18:53 +0000) committer Mark Spencer Sat, 4 Jan 2003 18:53:14 +0000 (18:53 +0000)

47 files changed:
 db1-ast/Makefile [new file with mode: 0755] patch | blob db1-ast/btree/bt_close.c [new file with mode: 0755] patch | blob db1-ast/btree/bt_conv.c [new file with mode: 0755] patch | blob db1-ast/btree/bt_debug.c [new file with mode: 0755] patch | blob db1-ast/btree/bt_delete.c [new file with mode: 0755] patch | blob db1-ast/btree/bt_get.c [new file with mode: 0755] patch | blob db1-ast/btree/bt_open.c [new file with mode: 0755] patch | blob db1-ast/btree/bt_overflow.c [new file with mode: 0755] patch | blob db1-ast/btree/bt_page.c [new file with mode: 0755] patch | blob db1-ast/btree/bt_put.c [new file with mode: 0755] patch | blob db1-ast/btree/bt_search.c [new file with mode: 0755] patch | blob db1-ast/btree/bt_seq.c [new file with mode: 0755] patch | blob db1-ast/btree/bt_split.c [new file with mode: 0755] patch | blob db1-ast/btree/bt_utils.c [new file with mode: 0755] patch | blob db1-ast/btree/btree.h [new file with mode: 0755] patch | blob db1-ast/btree/extern.h [new file with mode: 0755] patch | blob db1-ast/db/db.c [new file with mode: 0755] patch | blob db1-ast/hash/README [new file with mode: 0755] patch | blob db1-ast/hash/extern.h [new file with mode: 0755] patch | blob db1-ast/hash/hash.c [new file with mode: 0755] patch | blob db1-ast/hash/hash.h [new file with mode: 0755] patch | blob db1-ast/hash/hash_bigkey.c [new file with mode: 0755] patch | blob db1-ast/hash/hash_buf.c [new file with mode: 0755] patch | blob db1-ast/hash/hash_func.c [new file with mode: 0755] patch | blob db1-ast/hash/hash_log2.c [new file with mode: 0755] patch | blob db1-ast/hash/hash_page.c [new file with mode: 0755] patch | blob db1-ast/hash/hsearch.c [new file with mode: 0755] patch | blob db1-ast/hash/ndbm.c [new file with mode: 0755] patch | blob db1-ast/hash/page.h [new file with mode: 0755] patch | blob db1-ast/hash/search.h [new file with mode: 0755] patch | blob db1-ast/include/compat.h [new file with mode: 0755] patch | blob db1-ast/include/db.h [new file with mode: 0755] patch | blob db1-ast/include/mpool.h [new file with mode: 0755] patch | blob db1-ast/include/ndbm.h [new file with mode: 0755] patch | blob db1-ast/libdb.map [new file with mode: 0755] patch | blob db1-ast/mpool/README [new file with mode: 0755] patch | blob db1-ast/mpool/mpool.c [new file with mode: 0755] patch | blob db1-ast/recno/extern.h [new file with mode: 0755] patch | blob db1-ast/recno/rec_close.c [new file with mode: 0755] patch | blob db1-ast/recno/rec_delete.c [new file with mode: 0755] patch | blob db1-ast/recno/rec_get.c [new file with mode: 0755] patch | blob db1-ast/recno/rec_open.c [new file with mode: 0755] patch | blob db1-ast/recno/rec_put.c [new file with mode: 0755] patch | blob db1-ast/recno/rec_search.c [new file with mode: 0755] patch | blob db1-ast/recno/rec_seq.c [new file with mode: 0755] patch | blob db1-ast/recno/rec_utils.c [new file with mode: 0755] patch | blob db1-ast/recno/recno.h [new file with mode: 0755] patch | blob

diff --git a/db1-ast/Makefile b/db1-ast/Makefile
new file mode 100755 (executable)
index 0000000..8a945c2
--- /dev/null
@@ -0,0 +1,66 @@
+#      @(#)Makefile    8.9 (Berkeley) 7/14/94
+
+LIBDB= libdb1.a
+ARCH=\$(shell uname -m)
+ifeq (\$(ARCH),alpha)
+SOVER=2.1
+else
+SOVER=2
+endif
+LIBDBSO=libdb.so.\$(SOVER)
+PROG=  db_dump185
+OBJ1=  hash.o hash_bigkey.o hash_buf.o hash_func.o hash_log2.o hash_page.o \
+       ndbm.o
+OBJ2=  bt_close.o bt_conv.o bt_debug.o bt_delete.o bt_get.o bt_open.o \
+       bt_overflow.o bt_page.o bt_put.o bt_search.o bt_seq.o bt_split.o \
+       bt_utils.o
+OBJ3=  db.o
+OBJ4=  mpool.o
+OBJ5=  rec_close.o rec_delete.o rec_get.o rec_open.o rec_put.o rec_search.o \
+       rec_seq.o rec_utils.o
+MISC=
+OBJS=  \$(OBJ1) \$(OBJ2) \$(OBJ3) \$(OBJ4) \$(OBJ5) \$(MISC)
+SHOBJS=        \$(patsubst %.o,%.os,\$(OBJS))
+
+all: \$(LIBDB) #\$(LIBDBSO) \$(PROG)
+
+\$(LIBDB): \$(OBJS)
+       rm -f \$@
+       ar cq \$@ \$(OBJS)
+       ranlib \$@
+
+\$(LIBDBSO): \$(SHOBJS)
+       \$(CC) -Wl,-O1 -Wl,--version-script=libdb.map -Wl,-soname=\$(LIBDBSO) -shared -o \$@ \$^
+       ln -sf \$@ libdb.so
+
+\$(PROG): db_dump185.o \$(LIBDBSO)
+       \$(CC) -o \$@ db_dump185.o -L. -ldb
+
+clean:
+       rm -f \$(LIBDB) \$(LIBDBSO) \$(OBJS) \$(SHOBJS)
+
+OORG=  -O2
+CL=    \$(CC) -c -D__DBINTERFACE_PRIVATE \$(OORG) -I. -Iinclude
+
+db_dump185.o: db_dump185.c
+       \$(CL) -o \$@ \$<
+%.o: hash/%.c
+       \$(CL) -Ihash -o \$@ \$<
+%.os: hash/%.c
+       \$(CL) -Ihash -fPIC -o \$@ \$<
+%.o: btree/%.c
+       \$(CL) -Ibtree -o \$@ \$<
+%.os: btree/%.c
+       \$(CL) -Ibtree -fPIC -o \$@ \$<
+db.o: db/db.c
+       \$(CL) -o \$@ \$<
+db.os: db/db.c
+       \$(CL) -fPIC -o \$@ \$<
+mpool.o: mpool/mpool.c
+       \$(CL) -o \$@ \$<
+mpool.os: mpool/mpool.c
+       \$(CL) -fPIC -o \$@ \$<
+%.o: recno/%.c
+       \$(CL) -Irecno -o \$@ \$<
+%.os: recno/%.c
+       \$(CL) -Irecno -fPIC -o \$@ \$<
diff --git a/db1-ast/btree/bt_close.c b/db1-ast/btree/bt_close.c
new file mode 100755 (executable)
index 0000000..27f9ab6
--- /dev/null
@@ -0,0 +1,182 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *     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[] = "@(#)bt_close.c 8.7 (Berkeley) 8/17/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/param.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <db.h>
+#include "btree.h"
+
+static int bt_meta __P((BTREE *));
+
+/*
+ * BT_CLOSE -- Close a btree.
+ *
+ * Parameters:
+ *     dbp:    pointer to access method
+ *
+ * Returns:
+ *     RET_ERROR, RET_SUCCESS
+ */
+int
+__bt_close(dbp)
+       DB *dbp;
+{
+       BTREE *t;
+       int fd;
+
+       t = dbp->internal;
+
+       /* Toss any page pinned across calls. */
+       if (t->bt_pinned != NULL) {
+               mpool_put(t->bt_mp, t->bt_pinned, 0);
+               t->bt_pinned = NULL;
+       }
+
+       /* Sync the tree. */
+       if (__bt_sync(dbp, 0) == RET_ERROR)
+               return (RET_ERROR);
+
+       /* Close the memory pool. */
+       if (mpool_close(t->bt_mp) == RET_ERROR)
+               return (RET_ERROR);
+
+       /* Free random memory. */
+       if (t->bt_cursor.key.data != NULL) {
+               free(t->bt_cursor.key.data);
+               t->bt_cursor.key.size = 0;
+               t->bt_cursor.key.data = NULL;
+       }
+       if (t->bt_rkey.data) {
+               free(t->bt_rkey.data);
+               t->bt_rkey.size = 0;
+               t->bt_rkey.data = NULL;
+       }
+       if (t->bt_rdata.data) {
+               free(t->bt_rdata.data);
+               t->bt_rdata.size = 0;
+               t->bt_rdata.data = NULL;
+       }
+
+       fd = t->bt_fd;
+       free(t);
+       free(dbp);
+       return (close(fd) ? RET_ERROR : RET_SUCCESS);
+}
+
+/*
+ * BT_SYNC -- sync the btree to disk.
+ *
+ * Parameters:
+ *     dbp:    pointer to access method
+ *
+ * Returns:
+ *     RET_SUCCESS, RET_ERROR.
+ */
+int
+__bt_sync(dbp, flags)
+       const DB *dbp;
+       u_int flags;
+{
+       BTREE *t;
+       int status;
+
+       t = dbp->internal;
+
+       /* Toss any page pinned across calls. */
+       if (t->bt_pinned != NULL) {
+               mpool_put(t->bt_mp, t->bt_pinned, 0);
+               t->bt_pinned = NULL;
+       }
+
+       /* Sync doesn't currently take any flags. */
+       if (flags != 0) {
+               errno = EINVAL;
+               return (RET_ERROR);
+       }
+
+       if (F_ISSET(t, B_INMEM | B_RDONLY) || !F_ISSET(t, B_MODIFIED))
+               return (RET_SUCCESS);
+
+       if (F_ISSET(t, B_METADIRTY) && bt_meta(t) == RET_ERROR)
+               return (RET_ERROR);
+
+       if ((status = mpool_sync(t->bt_mp)) == RET_SUCCESS)
+               F_CLR(t, B_MODIFIED);
+
+       return (status);
+}
+
+/*
+ * BT_META -- write the tree meta data to disk.
+ *
+ * Parameters:
+ *     t:      tree
+ *
+ * Returns:
+ *     RET_ERROR, RET_SUCCESS
+ */
+static int
+bt_meta(t)
+       BTREE *t;
+{
+       BTMETA m;
+       void *p;
+
+       if ((p = mpool_get(t->bt_mp, P_META, 0)) == NULL)
+               return (RET_ERROR);
+
+       /* Fill in metadata. */
+       m.magic = BTREEMAGIC;
+       m.version = BTREEVERSION;
+       m.psize = t->bt_psize;
+       m.free = t->bt_free;
+       m.nrecs = t->bt_nrecs;
+       m.flags = F_ISSET(t, SAVEMETA);
+
+       memmove(p, &m, sizeof(BTMETA));
+       mpool_put(t->bt_mp, p, MPOOL_DIRTY);
+       return (RET_SUCCESS);
+}
diff --git a/db1-ast/btree/bt_conv.c b/db1-ast/btree/bt_conv.c
new file mode 100755 (executable)
index 0000000..1cb208b
--- /dev/null
@@ -0,0 +1,221 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *     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[] = "@(#)bt_conv.c  8.5 (Berkeley) 8/17/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/param.h>
+
+#include <stdio.h>
+
+#include <db.h>
+#include "btree.h"
+
+static void mswap __P((PAGE *));
+
+/*
+ * __BT_BPGIN, __BT_BPGOUT --
+ *     Convert host-specific number layout to/from the host-independent
+ *     format stored on disk.
+ *
+ * Parameters:
+ *     t:      tree
+ *     pg:     page number
+ *     h:      page to convert
+ */
+void
+__bt_pgin(t, pg, pp)
+       void *t;
+       pgno_t pg;
+       void *pp;
+{
+       PAGE *h;
+       indx_t i, top;
+       u_char flags;
+       char *p;
+
+       if (!F_ISSET(((BTREE *)t), B_NEEDSWAP))
+               return;
+       if (pg == P_META) {
+               mswap(pp);
+               return;
+       }
+
+       h = pp;
+       M_32_SWAP(h->pgno);
+       M_32_SWAP(h->prevpg);
+       M_32_SWAP(h->nextpg);
+       M_32_SWAP(h->flags);
+       M_16_SWAP(h->lower);
+       M_16_SWAP(h->upper);
+
+       top = NEXTINDEX(h);
+       if ((h->flags & P_TYPE) == P_BINTERNAL)
+               for (i = 0; i < top; i++) {
+                       M_16_SWAP(h->linp[i]);
+                       p = (char *)GETBINTERNAL(h, i);
+                       P_32_SWAP(p);
+                       p += sizeof(u_int32_t);
+                       P_32_SWAP(p);
+                       p += sizeof(pgno_t);
+                       if (*(u_char *)p & P_BIGKEY) {
+                               p += sizeof(u_char);
+                               P_32_SWAP(p);
+                               p += sizeof(pgno_t);
+                               P_32_SWAP(p);
+                       }
+               }
+       else if ((h->flags & P_TYPE) == P_BLEAF)
+               for (i = 0; i < top; i++) {
+                       M_16_SWAP(h->linp[i]);
+                       p = (char *)GETBLEAF(h, i);
+                       P_32_SWAP(p);
+                       p += sizeof(u_int32_t);
+                       P_32_SWAP(p);
+                       p += sizeof(u_int32_t);
+                       flags = *(u_char *)p;
+                       if (flags & (P_BIGKEY | P_BIGDATA)) {
+                               p += sizeof(u_char);
+                               if (flags & P_BIGKEY) {
+                                       P_32_SWAP(p);
+                                       p += sizeof(pgno_t);
+                                       P_32_SWAP(p);
+                               }
+                               if (flags & P_BIGDATA) {
+                                       p += sizeof(u_int32_t);
+                                       P_32_SWAP(p);
+                                       p += sizeof(pgno_t);
+                                       P_32_SWAP(p);
+                               }
+                       }
+               }
+}
+
+void
+__bt_pgout(t, pg, pp)
+       void *t;
+       pgno_t pg;
+       void *pp;
+{
+       PAGE *h;
+       indx_t i, top;
+       u_char flags;
+       char *p;
+
+       if (!F_ISSET(((BTREE *)t), B_NEEDSWAP))
+               return;
+       if (pg == P_META) {
+               mswap(pp);
+               return;
+       }
+
+       h = pp;
+       top = NEXTINDEX(h);
+       if ((h->flags & P_TYPE) == P_BINTERNAL)
+               for (i = 0; i < top; i++) {
+                       p = (char *)GETBINTERNAL(h, i);
+                       P_32_SWAP(p);
+                       p += sizeof(u_int32_t);
+                       P_32_SWAP(p);
+                       p += sizeof(pgno_t);
+                       if (*(u_char *)p & P_BIGKEY) {
+                               p += sizeof(u_char);
+                               P_32_SWAP(p);
+                               p += sizeof(pgno_t);
+                               P_32_SWAP(p);
+                       }
+                       M_16_SWAP(h->linp[i]);
+               }
+       else if ((h->flags & P_TYPE) == P_BLEAF)
+               for (i = 0; i < top; i++) {
+                       p = (char *)GETBLEAF(h, i);
+                       P_32_SWAP(p);
+                       p += sizeof(u_int32_t);
+                       P_32_SWAP(p);
+                       p += sizeof(u_int32_t);
+                       flags = *(u_char *)p;
+                       if (flags & (P_BIGKEY | P_BIGDATA)) {
+                               p += sizeof(u_char);
+                               if (flags & P_BIGKEY) {
+                                       P_32_SWAP(p);
+                                       p += sizeof(pgno_t);
+                                       P_32_SWAP(p);
+                               }
+                               if (flags & P_BIGDATA) {
+                                       p += sizeof(u_int32_t);
+                                       P_32_SWAP(p);
+                                       p += sizeof(pgno_t);
+                                       P_32_SWAP(p);
+                               }
+                       }
+                       M_16_SWAP(h->linp[i]);
+               }
+
+       M_32_SWAP(h->pgno);
+       M_32_SWAP(h->prevpg);
+       M_32_SWAP(h->nextpg);
+       M_32_SWAP(h->flags);
+       M_16_SWAP(h->lower);
+       M_16_SWAP(h->upper);
+}
+
+/*
+ * MSWAP -- Actually swap the bytes on the meta page.
+ *
+ * Parameters:
+ *     p:      page to convert
+ */
+static void
+mswap(pg)
+       PAGE *pg;
+{
+       char *p;
+
+       p = (char *)pg;
+       P_32_SWAP(p);           /* magic */
+       p += sizeof(u_int32_t);
+       P_32_SWAP(p);           /* version */
+       p += sizeof(u_int32_t);
+       P_32_SWAP(p);           /* psize */
+       p += sizeof(u_int32_t);
+       P_32_SWAP(p);           /* free */
+       p += sizeof(u_int32_t);
+       P_32_SWAP(p);           /* nrecs */
+       p += sizeof(u_int32_t);
+       P_32_SWAP(p);           /* flags */
+       p += sizeof(u_int32_t);
+}
diff --git a/db1-ast/btree/bt_debug.c b/db1-ast/btree/bt_debug.c
new file mode 100755 (executable)
index 0000000..3aefbe7
--- /dev/null
@@ -0,0 +1,329 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *     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[] = "@(#)bt_debug.c 8.5 (Berkeley) 8/17/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/param.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <db.h>
+#include "btree.h"
+
+#ifdef DEBUG
+/*
+ * BT_DUMP -- Dump the tree
+ *
+ * Parameters:
+ *     dbp:    pointer to the DB
+ */
+void
+__bt_dump(dbp)
+       DB *dbp;
+{
+       BTREE *t;
+       PAGE *h;
+       pgno_t i;
+       char *sep;
+
+       t = dbp->internal;
+       (void)fprintf(stderr, "%s: pgsz %d",
+           F_ISSET(t, B_INMEM) ? "memory" : "disk", t->bt_psize);
+       if (F_ISSET(t, R_RECNO))
+               (void)fprintf(stderr, " keys %lu", t->bt_nrecs);
+#undef X
+#define        X(flag, name) \
+       if (F_ISSET(t, flag)) { \
+               (void)fprintf(stderr, "%s%s", sep, name); \
+               sep = ", "; \
+       }
+       if (t->flags != 0) {
+               sep = " flags (";
+               X(R_FIXLEN,     "FIXLEN");
+               X(B_INMEM,      "INMEM");
+               X(B_NODUPS,     "NODUPS");
+               X(B_RDONLY,     "RDONLY");
+               X(R_RECNO,      "RECNO");
+               (void)fprintf(stderr, ")\n");
+       }
+#undef X
+
+       for (i = P_ROOT; (h = mpool_get(t->bt_mp, i, 0)) != NULL; ++i) {
+               __bt_dpage(h);
+               (void)mpool_put(t->bt_mp, h, 0);
+       }
+}
+
+/*
+ * BT_DMPAGE -- Dump the meta page
+ *
+ * Parameters:
+ *     h:      pointer to the PAGE
+ */
+void
+__bt_dmpage(h)
+       PAGE *h;
+{
+       BTMETA *m;
+       char *sep;
+
+       m = (BTMETA *)h;
+       (void)fprintf(stderr, "magic %lx\n", m->magic);
+       (void)fprintf(stderr, "version %lu\n", m->version);
+       (void)fprintf(stderr, "psize %lu\n", m->psize);
+       (void)fprintf(stderr, "free %lu\n", m->free);
+       (void)fprintf(stderr, "nrecs %lu\n", m->nrecs);
+       (void)fprintf(stderr, "flags %lu", m->flags);
+#undef X
+#define        X(flag, name) \
+       if (m->flags & flag) { \
+               (void)fprintf(stderr, "%s%s", sep, name); \
+               sep = ", "; \
+       }
+       if (m->flags) {
+               sep = " (";
+               X(B_NODUPS,     "NODUPS");
+               X(R_RECNO,      "RECNO");
+               (void)fprintf(stderr, ")");
+       }
+}
+
+/*
+ * BT_DNPAGE -- Dump the page
+ *
+ * Parameters:
+ *     n:      page number to dump.
+ */
+void
+__bt_dnpage(dbp, pgno)
+       DB *dbp;
+       pgno_t pgno;
+{
+       BTREE *t;
+       PAGE *h;
+
+       t = dbp->internal;
+       if ((h = mpool_get(t->bt_mp, pgno, 0)) != NULL) {
+               __bt_dpage(h);
+               (void)mpool_put(t->bt_mp, h, 0);
+       }
+}
+
+/*
+ * BT_DPAGE -- Dump the page
+ *
+ * Parameters:
+ *     h:      pointer to the PAGE
+ */
+void
+__bt_dpage(h)
+       PAGE *h;
+{
+       BINTERNAL *bi;
+       BLEAF *bl;
+       RINTERNAL *ri;
+       RLEAF *rl;
+       indx_t cur, top;
+       char *sep;
+
+       (void)fprintf(stderr, "    page %d: (", h->pgno);
+#undef X
+#define        X(flag, name) \
+       if (h->flags & flag) { \
+               (void)fprintf(stderr, "%s%s", sep, name); \
+               sep = ", "; \
+       }
+       sep = "";
+       X(P_BINTERNAL,  "BINTERNAL")            /* types */
+       X(P_BLEAF,      "BLEAF")
+       X(P_RINTERNAL,  "RINTERNAL")            /* types */
+       X(P_RLEAF,      "RLEAF")
+       X(P_OVERFLOW,   "OVERFLOW")
+       X(P_PRESERVE,   "PRESERVE");
+       (void)fprintf(stderr, ")\n");
+#undef X
+
+       (void)fprintf(stderr, "\tprev %2d next %2d", h->prevpg, h->nextpg);
+       if (h->flags & P_OVERFLOW)
+               return;
+
+       top = NEXTINDEX(h);
+       (void)fprintf(stderr, " lower %3d upper %3d nextind %d\n",
+           h->lower, h->upper, top);
+       for (cur = 0; cur < top; cur++) {
+               (void)fprintf(stderr, "\t[%03d] %4d ", cur, h->linp[cur]);
+               switch (h->flags & P_TYPE) {
+               case P_BINTERNAL:
+                       bi = GETBINTERNAL(h, cur);
+                       (void)fprintf(stderr,
+                           "size %03d pgno %03d", bi->ksize, bi->pgno);
+                       if (bi->flags & P_BIGKEY)
+                               (void)fprintf(stderr, " (indirect)");
+                       else if (bi->ksize)
+                               (void)fprintf(stderr,
+                                   " {%.*s}", (int)bi->ksize, bi->bytes);
+                       break;
+               case P_RINTERNAL:
+                       ri = GETRINTERNAL(h, cur);
+                       (void)fprintf(stderr, "entries %03d pgno %03d",
+                               ri->nrecs, ri->pgno);
+                       break;
+               case P_BLEAF:
+                       bl = GETBLEAF(h, cur);
+                       if (bl->flags & P_BIGKEY)
+                               (void)fprintf(stderr,
+                                   "big key page %lu size %u/",
+                                   *(pgno_t *)bl->bytes,
+                                   *(u_int32_t *)(bl->bytes + sizeof(pgno_t)));
+                       else if (bl->ksize)
+                               (void)fprintf(stderr, "%s/", bl->bytes);
+                       if (bl->flags & P_BIGDATA)
+                               (void)fprintf(stderr,
+                                   "big data page %lu size %u",
+                                   *(pgno_t *)(bl->bytes + bl->ksize),
+                                   *(u_int32_t *)(bl->bytes + bl->ksize +
+                                   sizeof(pgno_t)));
+                       else if (bl->dsize)
+                               (void)fprintf(stderr, "%.*s",
+                                   (int)bl->dsize, bl->bytes + bl->ksize);
+                       break;
+               case P_RLEAF:
+                       rl = GETRLEAF(h, cur);
+                       if (rl->flags & P_BIGDATA)
+                               (void)fprintf(stderr,
+                                   "big data page %lu size %u",
+                                   *(pgno_t *)rl->bytes,
+                                   *(u_int32_t *)(rl->bytes + sizeof(pgno_t)));
+                       else if (rl->dsize)
+                               (void)fprintf(stderr,
+                                   "%.*s", (int)rl->dsize, rl->bytes);
+                       break;
+               }
+               (void)fprintf(stderr, "\n");
+       }
+}
+#endif
+
+#ifdef STATISTICS
+/*
+ * BT_STAT -- Gather/print the tree statistics
+ *
+ * Parameters:
+ *     dbp:    pointer to the DB
+ */
+void
+__bt_stat(dbp)
+       DB *dbp;
+{
+       extern u_long bt_cache_hit, bt_cache_miss, bt_pfxsaved, bt_rootsplit;
+       extern u_long bt_sortsplit, bt_split;
+       BTREE *t;
+       PAGE *h;
+       pgno_t i, pcont, pinternal, pleaf;
+       u_long ifree, lfree, nkeys;
+       int levels;
+
+       t = dbp->internal;
+       pcont = pinternal = pleaf = 0;
+       nkeys = ifree = lfree = 0;
+       for (i = P_ROOT; (h = mpool_get(t->bt_mp, i, 0)) != NULL; ++i) {
+               switch (h->flags & P_TYPE) {
+               case P_BINTERNAL:
+               case P_RINTERNAL:
+                       ++pinternal;
+                       ifree += h->upper - h->lower;
+                       break;
+               case P_BLEAF:
+               case P_RLEAF:
+                       ++pleaf;
+                       lfree += h->upper - h->lower;
+                       nkeys += NEXTINDEX(h);
+                       break;
+               case P_OVERFLOW:
+                       ++pcont;
+                       break;
+               }
+               (void)mpool_put(t->bt_mp, h, 0);
+       }
+
+       /* Count the levels of the tree. */
+       for (i = P_ROOT, levels = 0 ;; ++levels) {
+               h = mpool_get(t->bt_mp, i, 0);
+               if (h->flags & (P_BLEAF|P_RLEAF)) {
+                       if (levels == 0)
+                               levels = 1;
+                       (void)mpool_put(t->bt_mp, h, 0);
+                       break;
+               }
+               i = F_ISSET(t, R_RECNO) ?
+                   GETRINTERNAL(h, 0)->pgno :
+                   GETBINTERNAL(h, 0)->pgno;
+               (void)mpool_put(t->bt_mp, h, 0);
+       }
+
+       (void)fprintf(stderr, "%d level%s with %ld keys",
+           levels, levels == 1 ? "" : "s", nkeys);
+       if (F_ISSET(t, R_RECNO))
+               (void)fprintf(stderr, " (%ld header count)", t->bt_nrecs);
+       (void)fprintf(stderr,
+           "\n%lu pages (leaf %ld, internal %ld, overflow %ld)\n",
+           pinternal + pleaf + pcont, pleaf, pinternal, pcont);
+       (void)fprintf(stderr, "%ld cache hits, %ld cache misses\n",
+           bt_cache_hit, bt_cache_miss);
+       (void)fprintf(stderr, "%ld splits (%ld root splits, %ld sort splits)\n",
+           bt_split, bt_rootsplit, bt_sortsplit);
+       pleaf *= t->bt_psize - BTDATAOFF;
+       if (pleaf)
+               (void)fprintf(stderr,
+                   "%.0f%% leaf fill (%ld bytes used, %ld bytes free)\n",
+                   ((double)(pleaf - lfree) / pleaf) * 100,
+                   pleaf - lfree, lfree);
+       pinternal *= t->bt_psize - BTDATAOFF;
+       if (pinternal)
+               (void)fprintf(stderr,
+                   "%.0f%% internal fill (%ld bytes used, %ld bytes free\n",
+                   ((double)(pinternal - ifree) / pinternal) * 100,
+                   pinternal - ifree, ifree);
+       if (bt_pfxsaved)
+               (void)fprintf(stderr, "prefix checking removed %lu bytes.\n",
+                   bt_pfxsaved);
+}
+#endif
diff --git a/db1-ast/btree/bt_delete.c b/db1-ast/btree/bt_delete.c
new file mode 100755 (executable)
index 0000000..b654c9f
--- /dev/null
@@ -0,0 +1,657 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *     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[] = "@(#)bt_delete.c        8.13 (Berkeley) 7/28/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <db.h>
+#include "btree.h"
+
+static int __bt_bdelete __P((BTREE *, const DBT *));
+static int __bt_curdel __P((BTREE *, const DBT *, PAGE *, u_int));
+static int __bt_pdelete __P((BTREE *, PAGE *));
+static int __bt_relink __P((BTREE *, PAGE *));
+static int __bt_stkacq __P((BTREE *, PAGE **, CURSOR *));
+
+/*
+ * __bt_delete
+ *     Delete the item(s) referenced by a key.
+ *
+ * Return RET_SPECIAL if the key is not found.
+ */
+int
+__bt_delete(dbp, key, flags)
+       const DB *dbp;
+       const DBT *key;
+       u_int flags;
+{
+       BTREE *t;
+       CURSOR *c;
+       PAGE *h;
+       int status;
+
+       t = dbp->internal;
+
+       /* Toss any page pinned across calls. */
+       if (t->bt_pinned != NULL) {
+               mpool_put(t->bt_mp, t->bt_pinned, 0);
+               t->bt_pinned = NULL;
+       }
+
+       /* Check for change to a read-only tree. */
+       if (F_ISSET(t, B_RDONLY)) {
+               errno = EPERM;
+               return (RET_ERROR);
+       }
+
+       switch (flags) {
+       case 0:
+               status = __bt_bdelete(t, key);
+               break;
+       case R_CURSOR:
+               /*
+                * If flags is R_CURSOR, delete the cursor.  Must already
+                * have started a scan and not have already deleted it.
+                */
+               c = &t->bt_cursor;
+               if (F_ISSET(c, CURS_INIT)) {
+                       if (F_ISSET(c, CURS_ACQUIRE | CURS_AFTER | CURS_BEFORE))
+                               return (RET_SPECIAL);
+                       if ((h = mpool_get(t->bt_mp, c->pg.pgno, 0)) == NULL)
+                               return (RET_ERROR);
+
+                       /*
+                        * If the page is about to be emptied, we'll need to
+                        * delete it, which means we have to acquire a stack.
+                        */
+                       if (NEXTINDEX(h) == 1)
+                               if (__bt_stkacq(t, &h, &t->bt_cursor))
+                                       return (RET_ERROR);
+
+                       status = __bt_dleaf(t, NULL, h, c->pg.index);
+
+                       if (NEXTINDEX(h) == 0 && status == RET_SUCCESS) {
+                               if (__bt_pdelete(t, h))
+                                       return (RET_ERROR);
+                       } else
+                               mpool_put(t->bt_mp,
+                                   h, status == RET_SUCCESS ? MPOOL_DIRTY : 0);
+                       break;
+               }
+               /* FALLTHROUGH */
+       default:
+               errno = EINVAL;
+               return (RET_ERROR);
+       }
+       if (status == RET_SUCCESS)
+               F_SET(t, B_MODIFIED);
+       return (status);
+}
+
+/*
+ * __bt_stkacq --
+ *     Acquire a stack so we can delete a cursor entry.
+ *
+ * Parameters:
+ *       t:    tree
+ *      hp:    pointer to current, pinned PAGE pointer
+ *       c:    pointer to the cursor
+ *
+ * Returns:
+ *     0 on success, 1 on failure
+ */
+static int
+__bt_stkacq(t, hp, c)
+       BTREE *t;
+       PAGE **hp;
+       CURSOR *c;
+{
+       BINTERNAL *bi;
+       EPG *e;
+       EPGNO *parent;
+       PAGE *h;
+       indx_t index;
+       pgno_t pgno;
+       recno_t nextpg, prevpg;
+       int exact, level;
+
+       /*
+        * Find the first occurrence of the key in the tree.  Toss the
+        * currently locked page so we don't hit an already-locked page.
+        */
+       h = *hp;
+       mpool_put(t->bt_mp, h, 0);
+       if ((e = __bt_search(t, &c->key, &exact)) == NULL)
+               return (1);
+       h = e->page;
+
+       /* See if we got it in one shot. */
+       if (h->pgno == c->pg.pgno)
+               goto ret;
+
+       /*
+        * Move right, looking for the page.  At each move we have to move
+        * up the stack until we don't have to move to the next page.  If
+        * we have to change pages at an internal level, we have to fix the
+        * stack back up.
+        */
+       while (h->pgno != c->pg.pgno) {
+               if ((nextpg = h->nextpg) == P_INVALID)
+                       break;
+               mpool_put(t->bt_mp, h, 0);
+
+               /* Move up the stack. */
+               for (level = 0; (parent = BT_POP(t)) != NULL; ++level) {
+                       /* Get the parent page. */
+                       if ((h = mpool_get(t->bt_mp, parent->pgno, 0)) == NULL)
+                               return (1);
+
+                       /* Move to the next index. */
+                       if (parent->index != NEXTINDEX(h) - 1) {
+                               index = parent->index + 1;
+                               BT_PUSH(t, h->pgno, index);
+                               break;
+                       }
+                       mpool_put(t->bt_mp, h, 0);
+               }
+
+               /* Restore the stack. */
+               while (level--) {
+                       /* Push the next level down onto the stack. */
+                       bi = GETBINTERNAL(h, index);
+                       pgno = bi->pgno;
+                       BT_PUSH(t, pgno, 0);
+
+                       /* Lose the currently pinned page. */
+                       mpool_put(t->bt_mp, h, 0);
+
+                       /* Get the next level down. */
+                       if ((h = mpool_get(t->bt_mp, pgno, 0)) == NULL)
+                               return (1);
+                       index = 0;
+               }
+               mpool_put(t->bt_mp, h, 0);
+               if ((h = mpool_get(t->bt_mp, nextpg, 0)) == NULL)
+                       return (1);
+       }
+
+       if (h->pgno == c->pg.pgno)
+               goto ret;
+
+       /* Reacquire the original stack. */
+       mpool_put(t->bt_mp, h, 0);
+       if ((e = __bt_search(t, &c->key, &exact)) == NULL)
+               return (1);
+       h = e->page;
+
+       /*
+        * Move left, looking for the page.  At each move we have to move
+        * up the stack until we don't have to change pages to move to the
+        * next page.  If we have to change pages at an internal level, we
+        * have to fix the stack back up.
+        */
+       while (h->pgno != c->pg.pgno) {
+               if ((prevpg = h->prevpg) == P_INVALID)
+                       break;
+               mpool_put(t->bt_mp, h, 0);
+
+               /* Move up the stack. */
+               for (level = 0; (parent = BT_POP(t)) != NULL; ++level) {
+                       /* Get the parent page. */
+                       if ((h = mpool_get(t->bt_mp, parent->pgno, 0)) == NULL)
+                               return (1);
+
+                       /* Move to the next index. */
+                       if (parent->index != 0) {
+                               index = parent->index - 1;
+                               BT_PUSH(t, h->pgno, index);
+                               break;
+                       }
+                       mpool_put(t->bt_mp, h, 0);
+               }
+
+               /* Restore the stack. */
+               while (level--) {
+                       /* Push the next level down onto the stack. */
+                       bi = GETBINTERNAL(h, index);
+                       pgno = bi->pgno;
+
+                       /* Lose the currently pinned page. */
+                       mpool_put(t->bt_mp, h, 0);
+
+                       /* Get the next level down. */
+                       if ((h = mpool_get(t->bt_mp, pgno, 0)) == NULL)
+                               return (1);
+
+                       index = NEXTINDEX(h) - 1;
+                       BT_PUSH(t, pgno, index);
+               }
+               mpool_put(t->bt_mp, h, 0);
+               if ((h = mpool_get(t->bt_mp, prevpg, 0)) == NULL)
+                       return (1);
+       }
+
+
+ret:   mpool_put(t->bt_mp, h, 0);
+       return ((*hp = mpool_get(t->bt_mp, c->pg.pgno, 0)) == NULL);
+}
+
+/*
+ * __bt_bdelete --
+ *     Delete all key/data pairs matching the specified key.
+ *
+ * Parameters:
+ *       t:    tree
+ *     key:    key to delete
+ *
+ * Returns:
+ *     RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key not found.
+ */
+static int
+__bt_bdelete(t, key)
+       BTREE *t;
+       const DBT *key;
+{
+       EPG *e;
+       PAGE *h;
+       int deleted, exact, redo;
+
+       deleted = 0;
+
+       /* Find any matching record; __bt_search pins the page. */
+loop:  if ((e = __bt_search(t, key, &exact)) == NULL)
+               return (deleted ? RET_SUCCESS : RET_ERROR);
+       if (!exact) {
+               mpool_put(t->bt_mp, e->page, 0);
+               return (deleted ? RET_SUCCESS : RET_SPECIAL);
+       }
+
+       /*
+        * Delete forward, then delete backward, from the found key.  If
+        * there are duplicates and we reach either side of the page, do
+        * the key search again, so that we get them all.
+        */
+       redo = 0;
+       h = e->page;
+       do {
+               if (__bt_dleaf(t, key, h, e->index)) {
+                       mpool_put(t->bt_mp, h, 0);
+                       return (RET_ERROR);
+               }
+               if (F_ISSET(t, B_NODUPS)) {
+                       if (NEXTINDEX(h) == 0) {
+                               if (__bt_pdelete(t, h))
+                                       return (RET_ERROR);
+                       } else
+                               mpool_put(t->bt_mp, h, MPOOL_DIRTY);
+                       return (RET_SUCCESS);
+               }
+               deleted = 1;
+       } while (e->index < NEXTINDEX(h) && __bt_cmp(t, key, e) == 0);
+
+       /* Check for right-hand edge of the page. */
+       if (e->index == NEXTINDEX(h))
+               redo = 1;
+
+       /* Delete from the key to the beginning of the page. */
+       while (e->index-- > 0) {
+               if (__bt_cmp(t, key, e) != 0)
+                       break;
+               if (__bt_dleaf(t, key, h, e->index) == RET_ERROR) {
+                       mpool_put(t->bt_mp, h, 0);
+                       return (RET_ERROR);
+               }
+               if (e->index == 0)
+                       redo = 1;
+       }
+
+       /* Check for an empty page. */
+       if (NEXTINDEX(h) == 0) {
+               if (__bt_pdelete(t, h))
+                       return (RET_ERROR);
+               goto loop;
+       }
+
+       /* Put the page. */
+       mpool_put(t->bt_mp, h, MPOOL_DIRTY);
+
+       if (redo)
+               goto loop;
+       return (RET_SUCCESS);
+}
+
+/*
+ * __bt_pdelete --
+ *     Delete a single page from the tree.
+ *
+ * Parameters:
+ *     t:      tree
+ *     h:      leaf page
+ *
+ * Returns:
+ *     RET_SUCCESS, RET_ERROR.
+ *
+ * Side-effects:
+ *     mpool_put's the page
+ */
+static int
+__bt_pdelete(t, h)
+       BTREE *t;
+       PAGE *h;
+{
+       BINTERNAL *bi;
+       PAGE *pg;
+       EPGNO *parent;
+       indx_t cnt, index, *ip, offset;
+       u_int32_t nksize;
+       char *from;
+
+       /*
+        * Walk the parent page stack -- a LIFO stack of the pages that were
+        * traversed when we searched for the page where the delete occurred.
+        * Each stack entry is a page number and a page index offset.  The
+        * offset is for the page traversed on the search.  We've just deleted
+        * a page, so we have to delete the key from the parent page.
+        *
+        * If the delete from the parent page makes it empty, this process may
+        * continue all the way up the tree.  We stop if we reach the root page
+        * (which is never deleted, it's just not worth the effort) or if the
+        * delete does not empty the page.
+        */
+       while ((parent = BT_POP(t)) != NULL) {
+               /* Get the parent page. */
+               if ((pg = mpool_get(t->bt_mp, parent->pgno, 0)) == NULL)
+                       return (RET_ERROR);
+
+               index = parent->index;
+               bi = GETBINTERNAL(pg, index);
+
+               /* Free any overflow pages. */
+               if (bi->flags & P_BIGKEY &&
+                   __ovfl_delete(t, bi->bytes) == RET_ERROR) {
+                       mpool_put(t->bt_mp, pg, 0);
+                       return (RET_ERROR);
+               }
+
+               /*
+                * Free the parent if it has only the one key and it's not the
+                * root page. If it's the rootpage, turn it back into an empty
+                * leaf page.
+                */
+               if (NEXTINDEX(pg) == 1) {
+                       if (pg->pgno == P_ROOT) {
+                               pg->lower = BTDATAOFF;
+                               pg->upper = t->bt_psize;
+                               pg->flags = P_BLEAF;
+                       } else {
+                               if (__bt_relink(t, pg) || __bt_free(t, pg))
+                                       return (RET_ERROR);
+                               continue;
+                       }
+               } else {
+                       /* Pack remaining key items at the end of the page. */
+                       nksize = NBINTERNAL(bi->ksize);
+                       from = (char *)pg + pg->upper;
+                       memmove(from + nksize, from, (char *)bi - from);
+                       pg->upper += nksize;
+
+                       /* Adjust indices' offsets, shift the indices down. */
+                       offset = pg->linp[index];
+                       for (cnt = index, ip = &pg->linp; cnt--; ++ip)
+                               if (ip < offset)
+                                       ip += nksize;
+                       for (cnt = NEXTINDEX(pg) - index; --cnt; ++ip)
+                               ip = ip < offset ? ip + nksize : ip;
+                       pg->lower -= sizeof(indx_t);
+               }
+
+               mpool_put(t->bt_mp, pg, MPOOL_DIRTY);
+               break;
+       }
+
+       /* Free the leaf page, as long as it wasn't the root. */
+       if (h->pgno == P_ROOT) {
+               mpool_put(t->bt_mp, h, MPOOL_DIRTY);
+               return (RET_SUCCESS);
+       }
+       return (__bt_relink(t, h) || __bt_free(t, h));
+}
+
+/*
+ * __bt_dleaf --
+ *     Delete a single record from a leaf page.
+ *
+ * Parameters:
+ *     t:      tree
+ *    key:     referenced key
+ *     h:      page
+ *     index:  index on page to delete
+ *
+ * Returns:
+ *     RET_SUCCESS, RET_ERROR.
+ */
+int
+__bt_dleaf(t, key, h, index)
+       BTREE *t;
+       const DBT *key;
+       PAGE *h;
+       u_int index;
+{
+       BLEAF *bl;
+       indx_t cnt, *ip, offset;
+       u_int32_t nbytes;
+       void *to;
+       char *from;
+
+       /* If this record is referenced by the cursor, delete the cursor. */
+       if (F_ISSET(&t->bt_cursor, CURS_INIT) &&
+           !F_ISSET(&t->bt_cursor, CURS_ACQUIRE) &&
+           t->bt_cursor.pg.pgno == h->pgno && t->bt_cursor.pg.index == index &&
+           __bt_curdel(t, key, h, index))
+               return (RET_ERROR);
+
+       /* If the entry uses overflow pages, make them available for reuse. */
+       to = bl = GETBLEAF(h, index);
+       if (bl->flags & P_BIGKEY && __ovfl_delete(t, bl->bytes) == RET_ERROR)
+               return (RET_ERROR);
+       if (bl->flags & P_BIGDATA &&
+           __ovfl_delete(t, bl->bytes + bl->ksize) == RET_ERROR)
+               return (RET_ERROR);
+
+       /* Pack the remaining key/data items at the end of the page. */
+       nbytes = NBLEAF(bl);
+       from = (char *)h + h->upper;
+       memmove(from + nbytes, from, (char *)to - from);
+       h->upper += nbytes;
+
+       /* Adjust the indices' offsets, shift the indices down. */
+       offset = h->linp[index];
+       for (cnt = index, ip = &h->linp; cnt--; ++ip)
+               if (ip < offset)
+                       ip += nbytes;
+       for (cnt = NEXTINDEX(h) - index; --cnt; ++ip)
+               ip = ip < offset ? ip + nbytes : ip;
+       h->lower -= sizeof(indx_t);
+
+       /* If the cursor is on this page, adjust it as necessary. */
+       if (F_ISSET(&t->bt_cursor, CURS_INIT) &&
+           !F_ISSET(&t->bt_cursor, CURS_ACQUIRE) &&
+           t->bt_cursor.pg.pgno == h->pgno && t->bt_cursor.pg.index > index)
+               --t->bt_cursor.pg.index;
+
+       return (RET_SUCCESS);
+}
+
+/*
+ * __bt_curdel --
+ *     Delete the cursor.
+ *
+ * Parameters:
+ *     t:      tree
+ *    key:     referenced key (or NULL)
+ *     h:      page
+ *  index:     index on page to delete
+ *
+ * Returns:
+ *     RET_SUCCESS, RET_ERROR.
+ */
+static int
+__bt_curdel(t, key, h, index)
+       BTREE *t;
+       const DBT *key;
+       PAGE *h;
+       u_int index;
+{
+       CURSOR *c;
+       EPG e;
+       PAGE *pg;
+       int curcopy, status;
+
+       /*
+        * If there are duplicates, move forward or backward to one.
+        * Otherwise, copy the key into the cursor area.
+        */
+       c = &t->bt_cursor;
+       F_CLR(c, CURS_AFTER | CURS_BEFORE | CURS_ACQUIRE);
+
+       curcopy = 0;
+       if (!F_ISSET(t, B_NODUPS)) {
+               /*
+                * We're going to have to do comparisons.  If we weren't
+                * provided a copy of the key, i.e. the user is deleting
+                * the current cursor position, get one.
+                */
+               if (key == NULL) {
+                       e.page = h;
+                       e.index = index;
+                       if ((status = __bt_ret(t, &e,
+                           &c->key, &c->key, NULL, NULL, 1)) != RET_SUCCESS)
+                               return (status);
+                       curcopy = 1;
+                       key = &c->key;
+               }
+               /* Check previous key, if not at the beginning of the page. */
+               if (index > 0) {
+                       e.page = h;
+                       e.index = index - 1;
+                       if (__bt_cmp(t, key, &e) == 0) {
+                               F_SET(c, CURS_BEFORE);
+                               goto dup2;
+                       }
+               }
+               /* Check next key, if not at the end of the page. */
+               if (index < NEXTINDEX(h) - 1) {
+                       e.page = h;
+                       e.index = index + 1;
+                       if (__bt_cmp(t, key, &e) == 0) {
+                               F_SET(c, CURS_AFTER);
+                               goto dup2;
+                       }
+               }
+               /* Check previous key if at the beginning of the page. */
+               if (index == 0 && h->prevpg != P_INVALID) {
+                       if ((pg = mpool_get(t->bt_mp, h->prevpg, 0)) == NULL)
+                               return (RET_ERROR);
+                       e.page = pg;
+                       e.index = NEXTINDEX(pg) - 1;
+                       if (__bt_cmp(t, key, &e) == 0) {
+                               F_SET(c, CURS_BEFORE);
+                               goto dup1;
+                       }
+                       mpool_put(t->bt_mp, pg, 0);
+               }
+               /* Check next key if at the end of the page. */
+               if (index == NEXTINDEX(h) - 1 && h->nextpg != P_INVALID) {
+                       if ((pg = mpool_get(t->bt_mp, h->nextpg, 0)) == NULL)
+                               return (RET_ERROR);
+                       e.page = pg;
+                       e.index = 0;
+                       if (__bt_cmp(t, key, &e) == 0) {
+                               F_SET(c, CURS_AFTER);
+dup1:                          mpool_put(t->bt_mp, pg, 0);
+dup2:                          c->pg.pgno = e.page->pgno;
+                               c->pg.index = e.index;
+                               return (RET_SUCCESS);
+                       }
+                       mpool_put(t->bt_mp, pg, 0);
+               }
+       }
+       e.page = h;
+       e.index = index;
+       if (curcopy || (status =
+           __bt_ret(t, &e, &c->key, &c->key, NULL, NULL, 1)) == RET_SUCCESS) {
+               F_SET(c, CURS_ACQUIRE);
+               return (RET_SUCCESS);
+       }
+       return (status);
+}
+
+/*
+ *     Link around a deleted page.
+ *
+ * Parameters:
+ *     t:      tree
+ *     h:      page to be deleted
+ */
+static int
+       BTREE *t;
+       PAGE *h;
+{
+       PAGE *pg;
+
+       if (h->nextpg != P_INVALID) {
+               if ((pg = mpool_get(t->bt_mp, h->nextpg, 0)) == NULL)
+                       return (RET_ERROR);
+               pg->prevpg = h->prevpg;
+               mpool_put(t->bt_mp, pg, MPOOL_DIRTY);
+       }
+       if (h->prevpg != P_INVALID) {
+               if ((pg = mpool_get(t->bt_mp, h->prevpg, 0)) == NULL)
+                       return (RET_ERROR);
+               pg->nextpg = h->nextpg;
+               mpool_put(t->bt_mp, pg, MPOOL_DIRTY);
+       }
+       return (0);
+}
diff --git a/db1-ast/btree/bt_get.c b/db1-ast/btree/bt_get.c
new file mode 100755 (executable)
index 0000000..74824c7
--- /dev/null
@@ -0,0 +1,105 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *     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[] = "@(#)bt_get.c   8.6 (Berkeley) 7/20/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdio.h>
+
+#include <db.h>
+#include "btree.h"
+
+/*
+ * __BT_GET -- Get a record from the btree.
+ *
+ * Parameters:
+ *     dbp:    pointer to access method
+ *     key:    key to find
+ *     data:   data to return
+ *     flag:   currently unused
+ *
+ * Returns:
+ *     RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key not found.
+ */
+int
+__bt_get(dbp, key, data, flags)
+       const DB *dbp;
+       const DBT *key;
+       DBT *data;
+       u_int flags;
+{
+       BTREE *t;
+       EPG *e;
+       int exact, status;
+
+       t = dbp->internal;
+
+       /* Toss any page pinned across calls. */
+       if (t->bt_pinned != NULL) {
+               mpool_put(t->bt_mp, t->bt_pinned, 0);
+               t->bt_pinned = NULL;
+       }
+
+       /* Get currently doesn't take any flags. */
+       if (flags) {
+               errno = EINVAL;
+               return (RET_ERROR);
+       }
+
+       if ((e = __bt_search(t, key, &exact)) == NULL)
+               return (RET_ERROR);
+       if (!exact) {
+               mpool_put(t->bt_mp, e->page, 0);
+               return (RET_SPECIAL);
+       }
+
+       status = __bt_ret(t, e, NULL, NULL, data, &t->bt_rdata, 0);
+
+       /*
+        * If the user is doing concurrent access, we copied the
+        * key/data, toss the page.
+        */
+       if (F_ISSET(t, B_DB_LOCK))
+               mpool_put(t->bt_mp, e->page, 0);
+       else
+               t->bt_pinned = e->page;
+       return (status);
+}
diff --git a/db1-ast/btree/bt_open.c b/db1-ast/btree/bt_open.c
new file mode 100755 (executable)
index 0000000..8c2f48e
--- /dev/null
@@ -0,0 +1,458 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *     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[] = "@(#)bt_open.c  8.10 (Berkeley) 8/17/94";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * Implementation of btree access method for 4.4BSD.
+ *
+ * The design here was originally based on that of the btree access method
+ * used in the Postgres database system at UC Berkeley.  This implementation
+ * is wholly independent of the Postgres code.
+ */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <db.h>
+#include "btree.h"
+
+#ifdef DEBUG
+#undef MINPSIZE
+#define        MINPSIZE        128
+#endif
+
+static int byteorder __P((void));
+static int nroot __P((BTREE *));
+static int tmp __P((void));
+
+/*
+ * __BT_OPEN -- Open a btree.
+ *
+ * Creates and fills a DB struct, and calls the routine that actually
+ * opens the btree.
+ *
+ * Parameters:
+ *     fname:  filename (NULL for in-memory trees)
+ *     flags:  open flag bits
+ *     mode:   open permission bits
+ *     b:      BTREEINFO pointer
+ *
+ * Returns:
+ *     NULL on failure, pointer to DB on success.
+ *
+ */
+DB *
+__bt_open(fname, flags, mode, openinfo, dflags)
+       const char *fname;
+       int flags, mode, dflags;
+       const BTREEINFO *openinfo;
+{
+       struct stat sb;
+       BTMETA m;
+       BTREE *t;
+       BTREEINFO b;
+       DB *dbp;
+       pgno_t ncache;
+       ssize_t nr;
+       int machine_lorder;
+
+       t = NULL;
+
+       /*
+        * Intention is to make sure all of the user's selections are okay
+        * here and then use them without checking.  Can't be complete, since
+        * we don't know the right page size, lorder or flags until the backing
+        * file is opened.  Also, the file's page size can cause the cachesize
+        * to change.
+        */
+       machine_lorder = byteorder();
+       if (openinfo) {
+               b = *openinfo;
+
+               /* Flags: R_DUP. */
+               if (b.flags & ~(R_DUP))
+                       goto einval;
+
+               /*
+                * Page size must be indx_t aligned and >= MINPSIZE.  Default
+                * page size is set farther on, based on the underlying file
+                * transfer size.
+                */
+               if (b.psize &&
+                   (b.psize < MINPSIZE || b.psize > MAX_PAGE_OFFSET + 1 ||
+                   b.psize & (sizeof(indx_t) - 1)))
+                       goto einval;
+
+               /* Minimum number of keys per page; absolute minimum is 2. */
+               if (b.minkeypage) {
+                       if (b.minkeypage < 2)
+                               goto einval;
+               } else
+                       b.minkeypage = DEFMINKEYPAGE;
+
+               /* If no comparison, use default comparison and prefix. */
+               if (b.compare == NULL) {
+                       b.compare = __bt_defcmp;
+                       if (b.prefix == NULL)
+                               b.prefix = __bt_defpfx;
+               }
+
+               if (b.lorder == 0)
+                       b.lorder = machine_lorder;
+       } else {
+               b.compare = __bt_defcmp;
+               b.cachesize = 0;
+               b.flags = 0;
+               b.lorder = machine_lorder;
+               b.minkeypage = DEFMINKEYPAGE;
+               b.prefix = __bt_defpfx;
+               b.psize = 0;
+       }
+
+       /* Check for the ubiquitous PDP-11. */
+       if (b.lorder != BIG_ENDIAN && b.lorder != LITTLE_ENDIAN)
+               goto einval;
+
+       /* Allocate and initialize DB and BTREE structures. */
+       if ((t = (BTREE *)malloc(sizeof(BTREE))) == NULL)
+               goto err;
+       memset(t, 0, sizeof(BTREE));
+       t->bt_fd = -1;                  /* Don't close unopened fd on error. */
+       t->bt_lorder = b.lorder;
+       t->bt_order = NOT;
+       t->bt_cmp = b.compare;
+       t->bt_pfx = b.prefix;
+       t->bt_rfd = -1;
+
+       if ((t->bt_dbp = dbp = (DB *)malloc(sizeof(DB))) == NULL)
+               goto err;
+       memset(t->bt_dbp, 0, sizeof(DB));
+       if (t->bt_lorder != machine_lorder)
+               F_SET(t, B_NEEDSWAP);
+
+       dbp->type = DB_BTREE;
+       dbp->internal = t;
+       dbp->close = __bt_close;
+       dbp->del = __bt_delete;
+       dbp->fd = __bt_fd;
+       dbp->get = __bt_get;
+       dbp->put = __bt_put;
+       dbp->seq = __bt_seq;
+       dbp->sync = __bt_sync;
+
+       /*
+        * If no file name was supplied, this is an in-memory btree and we
+        * open a backing temporary file.  Otherwise, it's a disk-based tree.
+        */
+       if (fname) {
+               switch (flags & O_ACCMODE) {
+               case O_RDONLY:
+                       F_SET(t, B_RDONLY);
+                       break;
+               case O_RDWR:
+                       break;
+               case O_WRONLY:
+               default:
+                       goto einval;
+               }
+
+               if ((t->bt_fd = open(fname, flags, mode)) < 0)
+                       goto err;
+
+       } else {
+               if ((flags & O_ACCMODE) != O_RDWR)
+                       goto einval;
+               if ((t->bt_fd = tmp()) == -1)
+                       goto err;
+               F_SET(t, B_INMEM);
+       }
+
+       if (fcntl(t->bt_fd, F_SETFD, 1) == -1)
+               goto err;
+
+       if (fstat(t->bt_fd, &sb))
+               goto err;
+       if (sb.st_size) {
+               if ((nr = read(t->bt_fd, &m, sizeof(BTMETA))) < 0)
+                       goto err;
+               if (nr != sizeof(BTMETA))
+                       goto eftype;
+
+               /*
+                * Read in the meta-data.  This can change the notion of what
+                * the lorder, page size and flags are, and, when the page size
+                * changes, the cachesize value can change too.  If the user
+                * specified the wrong byte order for an existing database, we
+                * don't bother to return an error, we just clear the NEEDSWAP
+                * bit.
+                */
+               if (m.magic == BTREEMAGIC)
+                       F_CLR(t, B_NEEDSWAP);
+               else {
+                       F_SET(t, B_NEEDSWAP);
+                       M_32_SWAP(m.magic);
+                       M_32_SWAP(m.version);
+                       M_32_SWAP(m.psize);
+                       M_32_SWAP(m.free);
+                       M_32_SWAP(m.nrecs);
+                       M_32_SWAP(m.flags);
+               }
+               if (m.magic != BTREEMAGIC || m.version != BTREEVERSION)
+                       goto eftype;
+               if (m.psize < MINPSIZE || m.psize > MAX_PAGE_OFFSET + 1 ||
+                   m.psize & (sizeof(indx_t) - 1))
+                       goto eftype;
+               if (m.flags & ~SAVEMETA)
+                       goto eftype;
+               b.psize = m.psize;
+               F_SET(t, m.flags);
+               t->bt_free = m.free;
+               t->bt_nrecs = m.nrecs;
+       } else {
+               /*
+                * Set the page size to the best value for I/O to this file.
+                * Don't overflow the page offset type.
+                */
+               if (b.psize == 0) {
+#ifdef _STATBUF_ST_BLKSIZE
+                       b.psize = sb.st_blksize;
+#endif
+                       if (b.psize < MINPSIZE)
+                               b.psize = MINPSIZE;
+                       if (b.psize > MAX_PAGE_OFFSET + 1)
+                               b.psize = MAX_PAGE_OFFSET + 1;
+               }
+
+               /* Set flag if duplicates permitted. */
+               if (!(b.flags & R_DUP))
+                       F_SET(t, B_NODUPS);
+
+               t->bt_free = P_INVALID;
+               t->bt_nrecs = 0;
+       }
+
+       t->bt_psize = b.psize;
+
+       /* Set the cache size; must be a multiple of the page size. */
+       if (b.cachesize && b.cachesize & (b.psize - 1))
+               b.cachesize += (~b.cachesize & (b.psize - 1)) + 1;
+       if (b.cachesize < b.psize * MINCACHE)
+               b.cachesize = b.psize * MINCACHE;
+
+       /* Calculate number of pages to cache. */
+       ncache = (b.cachesize + t->bt_psize - 1) / t->bt_psize;
+
+       /*
+        * The btree data structure requires that at least two keys can fit on
+        * a page, but other than that there's no fixed requirement.  The user
+        * specified a minimum number per page, and we translated that into the
+        * number of bytes a key/data pair can use before being placed on an
+        * overflow page.  This calculation includes the page header, the size
+        * of the index referencing the leaf item and the size of the leaf item
+        * structure.  Also, don't let the user specify a minkeypage such that
+        * a key/data pair won't fit even if both key and data are on overflow
+        * pages.
+        */
+       t->bt_ovflsize = (t->bt_psize - BTDATAOFF) / b.minkeypage -
+           (sizeof(indx_t) + NBLEAFDBT(0, 0));
+       if (t->bt_ovflsize < NBLEAFDBT(NOVFLSIZE, NOVFLSIZE) + sizeof(indx_t))
+               t->bt_ovflsize =
+                   NBLEAFDBT(NOVFLSIZE, NOVFLSIZE) + sizeof(indx_t);
+
+       /* Initialize the buffer pool. */
+       if ((t->bt_mp =
+           mpool_open(NULL, t->bt_fd, t->bt_psize, ncache)) == NULL)
+               goto err;
+       if (!F_ISSET(t, B_INMEM))
+               mpool_filter(t->bt_mp, __bt_pgin, __bt_pgout, t);
+
+       /* Create a root page if new tree. */
+       if (nroot(t) == RET_ERROR)
+               goto err;
+
+       /* Global flags. */
+       if (dflags & DB_LOCK)
+               F_SET(t, B_DB_LOCK);
+       if (dflags & DB_SHMEM)
+               F_SET(t, B_DB_SHMEM);
+       if (dflags & DB_TXN)
+               F_SET(t, B_DB_TXN);
+
+       return (dbp);
+
+einval:        errno = EINVAL;
+       goto err;
+
+eftype:        errno = EFTYPE;
+       goto err;
+
+err:   if (t) {
+               if (t->bt_dbp)
+                       free(t->bt_dbp);
+               if (t->bt_fd != -1)
+                       (void)close(t->bt_fd);
+               free(t);
+       }
+       return (NULL);
+}
+
+/*
+ * NROOT -- Create the root of a new tree.
+ *
+ * Parameters:
+ *     t:      tree
+ *
+ * Returns:
+ *     RET_ERROR, RET_SUCCESS
+ */
+static int
+nroot(t)
+       BTREE *t;
+{
+       PAGE *meta, *root;
+       pgno_t npg;
+
+       if ((meta = mpool_get(t->bt_mp, 0, 0)) != NULL) {
+               mpool_put(t->bt_mp, meta, 0);
+               return (RET_SUCCESS);
+       }
+       if (errno != EINVAL)            /* It's OK to not exist. */
+               return (RET_ERROR);
+       errno = 0;
+
+       if ((meta = mpool_new(t->bt_mp, &npg)) == NULL)
+               return (RET_ERROR);
+
+       if ((root = mpool_new(t->bt_mp, &npg)) == NULL)
+               return (RET_ERROR);
+
+       if (npg != P_ROOT)
+               return (RET_ERROR);
+       root->pgno = npg;
+       root->prevpg = root->nextpg = P_INVALID;
+       root->lower = BTDATAOFF;
+       root->upper = t->bt_psize;
+       root->flags = P_BLEAF;
+       memset(meta, 0, t->bt_psize);
+       mpool_put(t->bt_mp, meta, MPOOL_DIRTY);
+       mpool_put(t->bt_mp, root, MPOOL_DIRTY);
+       return (RET_SUCCESS);
+}
+
+static int
+tmp()
+{
+       sigset_t set, oset;
+       int fd;
+       const char *envtmp;
+       char *path;
+       static const char fmt[] = "%s/bt.XXXXXX";
+       size_t n;
+
+       envtmp = getenv("TMPDIR");
+       if (!envtmp)
+         envtmp = "/tmp";
+       n = strlen (envtmp) + sizeof fmt;
+#ifdef __GNUC__
+       path = __builtin_alloca(n);
+#else
+       path = malloc(n);
+#endif
+       (void)snprintf(path, n, fmt, envtmp ? envtmp : "/tmp");
+
+       (void)sigfillset(&set);
+       if ((fd = mkstemp(path)) != -1)
+#ifndef        __GNUC__
+       free(path);
+#endif
+       return(fd);
+}
+
+static int
+byteorder()
+{
+       u_int32_t x;
+       u_char *p;
+
+       x = 0x01020304;
+       p = (u_char *)&x;
+       switch (*p) {
+       case 1:
+               return (BIG_ENDIAN);
+       case 4:
+               return (LITTLE_ENDIAN);
+       default:
+               return (0);
+       }
+}
+
+int
+__bt_fd(dbp)
+        const DB *dbp;
+{
+       BTREE *t;
+
+       t = dbp->internal;
+
+       /* Toss any page pinned across calls. */
+       if (t->bt_pinned != NULL) {
+               mpool_put(t->bt_mp, t->bt_pinned, 0);
+               t->bt_pinned = NULL;
+       }
+
+       /* In-memory database can't have a file descriptor. */
+       if (F_ISSET(t, B_INMEM)) {
+               errno = ENOENT;
+               return (-1);
+       }
+       return (t->bt_fd);
+}
diff --git a/db1-ast/btree/bt_overflow.c b/db1-ast/btree/bt_overflow.c
new file mode 100755 (executable)
index 0000000..b28b8e0
--- /dev/null
@@ -0,0 +1,228 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *     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[] = "@(#)bt_overflow.c      8.5 (Berkeley) 7/16/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/param.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <db.h>
+#include "btree.h"
+
+/*
+ * Big key/data code.
+ *
+ * Big key and data entries are stored on linked lists of pages.  The initial
+ * reference is byte string stored with the key or data and is the page number
+ * and size.  The actual record is stored in a chain of pages linked by the
+ * nextpg field of the PAGE header.
+ *
+ * The first page of the chain has a special property.  If the record is used
+ * by an internal page, it cannot be deleted and the P_PRESERVE bit will be set
+ *
+ * XXX
+ * A single DBT is written to each chain, so a lot of space on the last page
+ * is wasted.  This is a fairly major bug for some data sets.
+ */
+
+/*
+ * __OVFL_GET -- Get an overflow key/data item.
+ *
+ * Parameters:
+ *     t:      tree
+ *     p:      pointer to { pgno_t, u_int32_t }
+ *     bufsz:  storage size
+ *
+ * Returns:
+ *     RET_ERROR, RET_SUCCESS
+ */
+int
+__ovfl_get(t, p, ssz, buf, bufsz)
+       BTREE *t;
+       void *p;
+       size_t *ssz;
+       void **buf;
+       size_t *bufsz;
+{
+       PAGE *h;
+       pgno_t pg;
+       size_t nb, plen;
+       u_int32_t sz;
+
+       memmove(&pg, p, sizeof(pgno_t));
+       memmove(&sz, (char *)p + sizeof(pgno_t), sizeof(u_int32_t));
+       *ssz = sz;
+
+#ifdef DEBUG
+       if (pg == P_INVALID || sz == 0)
+               abort();
+#endif
+       /* Make the buffer bigger as necessary. */
+       if (*bufsz < sz) {
+               *buf = (char *)(*buf == NULL ? malloc(sz) : realloc(*buf, sz));
+               if (*buf == NULL)
+                       return (RET_ERROR);
+               *bufsz = sz;
+       }
+
+       /*
+        * Step through the linked list of pages, copying the data on each one
+        * into the buffer.  Never copy more than the data's length.
+        */
+       plen = t->bt_psize - BTDATAOFF;
+       for (p = *buf;; p = (char *)p + nb, pg = h->nextpg) {
+               if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
+                       return (RET_ERROR);
+
+               nb = MIN(sz, plen);
+               memmove(p, (char *)h + BTDATAOFF, nb);
+               mpool_put(t->bt_mp, h, 0);
+
+               if ((sz -= nb) == 0)
+                       break;
+       }
+       return (RET_SUCCESS);
+}
+
+/*
+ * __OVFL_PUT -- Store an overflow key/data item.
+ *
+ * Parameters:
+ *     t:      tree
+ *     data:   DBT to store
+ *     pgno:   storage page number
+ *
+ * Returns:
+ *     RET_ERROR, RET_SUCCESS
+ */
+int
+__ovfl_put(t, dbt, pg)
+       BTREE *t;
+       const DBT *dbt;
+       pgno_t *pg;
+{
+       PAGE *h, *last;
+       void *p;
+       pgno_t npg;
+       size_t nb, plen;
+       u_int32_t sz;
+
+       /*
+        * Allocate pages and copy the key/data record into them.  Store the
+        * number of the first page in the chain.
+        */
+       plen = t->bt_psize - BTDATAOFF;
+       for (last = NULL, p = dbt->data, sz = dbt->size;;
+           p = (char *)p + plen, last = h) {
+               if ((h = __bt_new(t, &npg)) == NULL)
+                       return (RET_ERROR);
+
+               h->pgno = npg;
+               h->nextpg = h->prevpg = P_INVALID;
+               h->flags = P_OVERFLOW;
+               h->lower = h->upper = 0;
+
+               nb = MIN(sz, plen);
+               memmove((char *)h + BTDATAOFF, p, nb);
+
+               if (last) {
+                       last->nextpg = h->pgno;
+                       mpool_put(t->bt_mp, last, MPOOL_DIRTY);
+               } else
+                       *pg = h->pgno;
+
+               if ((sz -= nb) == 0) {
+                       mpool_put(t->bt_mp, h, MPOOL_DIRTY);
+                       break;
+               }
+       }
+       return (RET_SUCCESS);
+}
+
+/*
+ * __OVFL_DELETE -- Delete an overflow chain.
+ *
+ * Parameters:
+ *     t:      tree
+ *     p:      pointer to { pgno_t, u_int32_t }
+ *
+ * Returns:
+ *     RET_ERROR, RET_SUCCESS
+ */
+int
+__ovfl_delete(t, p)
+       BTREE *t;
+       void *p;
+{
+       PAGE *h;
+       pgno_t pg;
+       size_t plen;
+       u_int32_t sz;
+
+       memmove(&pg, p, sizeof(pgno_t));
+       memmove(&sz, (char *)p + sizeof(pgno_t), sizeof(u_int32_t));
+
+#ifdef DEBUG
+       if (pg == P_INVALID || sz == 0)
+               abort();
+#endif
+       if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
+               return (RET_ERROR);
+
+       /* Don't delete chains used by internal pages. */
+       if (h->flags & P_PRESERVE) {
+               mpool_put(t->bt_mp, h, 0);
+               return (RET_SUCCESS);
+       }
+
+       /* Step through the chain, calling the free routine for each page. */
+       for (plen = t->bt_psize - BTDATAOFF;; sz -= plen) {
+               pg = h->nextpg;
+               __bt_free(t, h);
+               if (sz <= plen)
+                       break;
+               if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
+                       return (RET_ERROR);
+       }
+       return (RET_SUCCESS);
+}
diff --git a/db1-ast/btree/bt_page.c b/db1-ast/btree/bt_page.c
new file mode 100755 (executable)
index 0000000..ce9cbf1
--- /dev/null
@@ -0,0 +1,100 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *     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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)bt_page.c  8.3 (Berkeley) 7/14/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+
+#include <stdio.h>
+
+#include <db.h>
+#include "btree.h"
+
+/*
+ * __bt_free --
+ *     Put a page on the freelist.
+ *
+ * Parameters:
+ *     t:      tree
+ *     h:      page to free
+ *
+ * Returns:
+ *     RET_ERROR, RET_SUCCESS
+ *
+ * Side-effect:
+ *     mpool_put's the page.
+ */
+int
+__bt_free(t, h)
+       BTREE *t;
+       PAGE *h;
+{
+       /* Insert the page at the head of the free list. */
+       h->prevpg = P_INVALID;
+       h->nextpg = t->bt_free;
+       t->bt_free = h->pgno;
+
+       /* Make sure the page gets written back. */
+       return (mpool_put(t->bt_mp, h, MPOOL_DIRTY));
+}
+
+/*
+ * __bt_new --
+ *     Get a new page, preferably from the freelist.
+ *
+ * Parameters:
+ *     t:      tree
+ *     npg:    storage for page number.
+ *
+ * Returns:
+ *     Pointer to a page, NULL on error.
+ */
+PAGE *
+__bt_new(t, npg)
+       BTREE *t;
+       pgno_t *npg;
+{
+       PAGE *h;
+
+       if (t->bt_free != P_INVALID &&
+           (h = mpool_get(t->bt_mp, t->bt_free, 0)) != NULL) {
+               *npg = t->bt_free;
+               t->bt_free = h->nextpg;
+               return (h);
+       }
+       return (mpool_new(t->bt_mp, npg));
+}
diff --git a/db1-ast/btree/bt_put.c b/db1-ast/btree/bt_put.c
new file mode 100755 (executable)
index 0000000..15309c6
--- /dev/null
@@ -0,0 +1,321 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *     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[] = "@(#)bt_put.c   8.8 (Berkeley) 7/26/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <db.h>
+#include "btree.h"
+
+static EPG *bt_fast __P((BTREE *, const DBT *, const DBT *, int *));
+
+/*
+ * __BT_PUT -- Add a btree item to the tree.
+ *
+ * Parameters:
+ *     dbp:    pointer to access method
+ *     key:    key
+ *     data:   data
+ *     flag:   R_NOOVERWRITE
+ *
+ * Returns:
+ *     RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key is already in the
+ *     tree and R_NOOVERWRITE specified.
+ */
+int
+__bt_put(dbp, key, data, flags)
+       const DB *dbp;
+       DBT *key;
+       const DBT *data;
+       u_int flags;
+{
+       BTREE *t;
+       DBT tkey, tdata;
+       EPG *e;
+       PAGE *h;
+       indx_t index, nxtindex;
+       pgno_t pg;
+       u_int32_t nbytes;
+       int dflags, exact, status;
+       char *dest, db[NOVFLSIZE], kb[NOVFLSIZE];
+
+       t = dbp->internal;
+
+       /* Toss any page pinned across calls. */
+       if (t->bt_pinned != NULL) {
+               mpool_put(t->bt_mp, t->bt_pinned, 0);
+               t->bt_pinned = NULL;
+       }
+
+       /* Check for change to a read-only tree. */
+       if (F_ISSET(t, B_RDONLY)) {
+               errno = EPERM;
+               return (RET_ERROR);
+       }
+
+       switch (flags) {
+       case 0:
+       case R_NOOVERWRITE:
+               break;
+       case R_CURSOR:
+               /*
+                * If flags is R_CURSOR, put the cursor.  Must already
+                * have started a scan and not have already deleted it.
+                */
+               if (F_ISSET(&t->bt_cursor, CURS_INIT) &&
+                   !F_ISSET(&t->bt_cursor,
+                       CURS_ACQUIRE | CURS_AFTER | CURS_BEFORE))
+                       break;
+               /* FALLTHROUGH */
+       default:
+               errno = EINVAL;
+               return (RET_ERROR);
+       }
+
+       /*
+        * If the key/data pair won't fit on a page, store it on overflow
+        * pages.  Only put the key on the overflow page if the pair are
+        * still too big after moving the data to an overflow page.
+        *
+        * XXX
+        * If the insert fails later on, the overflow pages aren't recovered.
+        */
+       dflags = 0;
+       if (key->size + data->size > t->bt_ovflsize) {
+               if (key->size > t->bt_ovflsize) {
+storekey:              if (__ovfl_put(t, key, &pg) == RET_ERROR)
+                               return (RET_ERROR);
+                       tkey.data = kb;
+                       tkey.size = NOVFLSIZE;
+                       memmove(kb, &pg, sizeof(pgno_t));
+                       memmove(kb + sizeof(pgno_t),
+                           &key->size, sizeof(u_int32_t));
+                       dflags |= P_BIGKEY;
+                       key = &tkey;
+               }
+               if (key->size + data->size > t->bt_ovflsize) {
+                       if (__ovfl_put(t, data, &pg) == RET_ERROR)
+                               return (RET_ERROR);
+                       tdata.data = db;
+                       tdata.size = NOVFLSIZE;
+                       memmove(db, &pg, sizeof(pgno_t));
+                       memmove(db + sizeof(pgno_t),
+                           &data->size, sizeof(u_int32_t));
+                       dflags |= P_BIGDATA;
+                       data = &tdata;
+               }
+               if (key->size + data->size > t->bt_ovflsize)
+                       goto storekey;
+       }
+
+       /* Replace the cursor. */
+       if (flags == R_CURSOR) {
+               if ((h = mpool_get(t->bt_mp, t->bt_cursor.pg.pgno, 0)) == NULL)
+                       return (RET_ERROR);
+               index = t->bt_cursor.pg.index;
+               goto delete;
+       }
+
+       /*
+        * Find the key to delete, or, the location at which to insert.
+        * Bt_fast and __bt_search both pin the returned page.
+        */
+       if (t->bt_order == NOT || (e = bt_fast(t, key, data, &exact)) == NULL)
+               if ((e = __bt_search(t, key, &exact)) == NULL)
+                       return (RET_ERROR);
+       h = e->page;
+       index = e->index;
+
+       /*
+        * Add the key/data pair to the tree.  If an identical key is already
+        * in the tree, and R_NOOVERWRITE is set, an error is returned.  If
+        * R_NOOVERWRITE is not set, the key is either added (if duplicates are
+        * permitted) or an error is returned.
+        */
+       switch (flags) {
+       case R_NOOVERWRITE:
+               if (!exact)
+                       break;
+               mpool_put(t->bt_mp, h, 0);
+               return (RET_SPECIAL);
+       default:
+               if (!exact || !F_ISSET(t, B_NODUPS))
+                       break;
+               /*
+                * !!!
+                * Note, the delete may empty the page, so we need to put a
+                * new entry into the page immediately.
+                */
+delete:                if (__bt_dleaf(t, key, h, index) == RET_ERROR) {
+                       mpool_put(t->bt_mp, h, 0);
+                       return (RET_ERROR);
+               }
+               break;
+       }
+
+       /*
+        * If not enough room, or the user has put a ceiling on the number of
+        * keys permitted in the page, split the page.  The split code will
+        * insert the key and data and unpin the current page.  If inserting
+        * into the offset array, shift the pointers up.
+        */
+       nbytes = NBLEAFDBT(key->size, data->size);
+       if ((u_int32_t) (h->upper - h->lower) < nbytes + sizeof(indx_t)) {
+               if ((status = __bt_split(t, h, key,
+                   data, dflags, nbytes, index)) != RET_SUCCESS)
+                       return (status);
+               goto success;
+       }
+
+       if (index < (nxtindex = NEXTINDEX(h)))
+               memmove(h->linp + index + 1, h->linp + index,
+                   (nxtindex - index) * sizeof(indx_t));
+       h->lower += sizeof(indx_t);
+
+       h->linp[index] = h->upper -= nbytes;
+       dest = (char *)h + h->upper;
+       WR_BLEAF(dest, key, data, dflags);
+
+       /* If the cursor is on this page, adjust it as necessary. */
+       if (F_ISSET(&t->bt_cursor, CURS_INIT) &&
+           !F_ISSET(&t->bt_cursor, CURS_ACQUIRE) &&
+           t->bt_cursor.pg.pgno == h->pgno && t->bt_cursor.pg.index >= index)
+               ++t->bt_cursor.pg.index;
+
+       if (t->bt_order == NOT) {
+               if (h->nextpg == P_INVALID) {
+                       if (index == NEXTINDEX(h) - 1) {
+                               t->bt_order = FORWARD;
+                               t->bt_last.index = index;
+                               t->bt_last.pgno = h->pgno;
+                       }
+               } else if (h->prevpg == P_INVALID) {
+                       if (index == 0) {
+                               t->bt_order = BACK;
+                               t->bt_last.index = 0;
+                               t->bt_last.pgno = h->pgno;
+                       }
+               }
+       }
+
+       mpool_put(t->bt_mp, h, MPOOL_DIRTY);
+
+success:
+       if (flags == R_SETCURSOR)
+               __bt_setcur(t, e->page->pgno, e->index);
+
+       F_SET(t, B_MODIFIED);
+       return (RET_SUCCESS);
+}
+
+#ifdef STATISTICS
+u_long bt_cache_hit, bt_cache_miss;
+#endif
+
+/*
+ * BT_FAST -- Do a quick check for sorted data.
+ *
+ * Parameters:
+ *     t:      tree
+ *     key:    key to insert
+ *
+ * Returns:
+ *     EPG for new record or NULL if not found.
+ */
+static EPG *
+bt_fast(t, key, data, exactp)
+       BTREE *t;
+       const DBT *key, *data;
+       int *exactp;
+{
+       PAGE *h;
+       u_int32_t nbytes;
+       int cmp;
+
+       if ((h = mpool_get(t->bt_mp, t->bt_last.pgno, 0)) == NULL) {
+               t->bt_order = NOT;
+               return (NULL);
+       }
+       t->bt_cur.page = h;
+       t->bt_cur.index = t->bt_last.index;
+
+       /*
+        * If won't fit in this page or have too many keys in this page,
+        * have to search to get split stack.
+        */
+       nbytes = NBLEAFDBT(key->size, data->size);
+       if ((u_int32_t) (h->upper - h->lower) < nbytes + sizeof(indx_t))
+               goto miss;
+
+       if (t->bt_order == FORWARD) {
+               if (t->bt_cur.page->nextpg != P_INVALID)
+                       goto miss;
+               if (t->bt_cur.index != NEXTINDEX(h) - 1)
+                       goto miss;
+               if ((cmp = __bt_cmp(t, key, &t->bt_cur)) < 0)
+                       goto miss;
+               t->bt_last.index = cmp ? ++t->bt_cur.index : t->bt_cur.index;
+       } else {
+               if (t->bt_cur.page->prevpg != P_INVALID)
+                       goto miss;
+               if (t->bt_cur.index != 0)
+                       goto miss;
+               if ((cmp = __bt_cmp(t, key, &t->bt_cur)) > 0)
+                       goto miss;
+               t->bt_last.index = 0;
+       }
+       *exactp = cmp == 0;
+#ifdef STATISTICS
+       ++bt_cache_hit;
+#endif
+       return (&t->bt_cur);
+
+miss:
+#ifdef STATISTICS
+       ++bt_cache_miss;
+#endif
+       t->bt_order = NOT;
+       mpool_put(t->bt_mp, h, 0);
+       return (NULL);
+}
diff --git a/db1-ast/btree/bt_search.c b/db1-ast/btree/bt_search.c
new file mode 100755 (executable)
index 0000000..485afcb
--- /dev/null
@@ -0,0 +1,213 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *     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[] = "@(#)bt_search.c        8.8 (Berkeley) 7/31/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+
+#include <stdio.h>
+
+#include <db.h>
+#include "btree.h"
+
+static int __bt_snext __P((BTREE *, PAGE *, const DBT *, int *));
+static int __bt_sprev __P((BTREE *, PAGE *, const DBT *, int *));
+
+/*
+ * __bt_search --
+ *     Search a btree for a key.
+ *
+ * Parameters:
+ *     t:      tree to search
+ *     key:    key to find
+ *     exactp: pointer to exact match flag
+ *
+ * Returns:
+ *     The EPG for matching record, if any, or the EPG for the location
+ *     of the key, if it were inserted into the tree, is entered into
+ *     the bt_cur field of the tree.  A pointer to the field is returned.
+ */
+EPG *
+__bt_search(t, key, exactp)
+       BTREE *t;
+       const DBT *key;
+       int *exactp;
+{
+       PAGE *h;
+       indx_t base, index, lim;
+       pgno_t pg;
+       int cmp;
+
+       BT_CLR(t);
+       for (pg = P_ROOT;;) {
+               if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
+                       return (NULL);
+
+               /* Do a binary search on the current page. */
+               t->bt_cur.page = h;
+               for (base = 0, lim = NEXTINDEX(h); lim; lim >>= 1) {
+                       t->bt_cur.index = index = base + (lim >> 1);
+                       if ((cmp = __bt_cmp(t, key, &t->bt_cur)) == 0) {
+                               if (h->flags & P_BLEAF) {
+                                       *exactp = 1;
+                                       return (&t->bt_cur);
+                               }
+                               goto next;
+                       }
+                       if (cmp > 0) {
+                               base = index + 1;
+                               --lim;
+                       }
+               }
+
+               /*
+                * If it's a leaf page, we're almost done.  If no duplicates
+                * are allowed, or we have an exact match, we're done.  Else,
+                * it's possible that there were matching keys on this page,
+                * which later deleted, and we're on a page with no matches
+                * while there are matches on other pages.  If at the start or
+                * end of a page, check the adjacent page.
+                */
+               if (h->flags & P_BLEAF) {
+                       if (!F_ISSET(t, B_NODUPS)) {
+                               if (base == 0 &&
+                                   h->prevpg != P_INVALID &&
+                                   __bt_sprev(t, h, key, exactp))
+                                       return (&t->bt_cur);
+                               if (base == NEXTINDEX(h) &&
+                                   h->nextpg != P_INVALID &&
+                                   __bt_snext(t, h, key, exactp))
+                                       return (&t->bt_cur);
+                       }
+                       *exactp = 0;
+                       t->bt_cur.index = base;
+                       return (&t->bt_cur);
+               }
+
+               /*
+                * No match found.  Base is the smallest index greater than
+                * key and may be zero or a last + 1 index.  If it's non-zero,
+                * decrement by one, and record the internal page which should
+                * be a parent page for the key.  If a split later occurs, the
+                * inserted page will be to the right of the saved page.
+                */
+               index = base ? base - 1 : base;
+
+next:          BT_PUSH(t, h->pgno, index);
+               pg = GETBINTERNAL(h, index)->pgno;
+               mpool_put(t->bt_mp, h, 0);
+       }
+}
+
+/*
+ * __bt_snext --
+ *     Check for an exact match after the key.
+ *
+ * Parameters:
+ *     t:      tree
+ *     h:      current page
+ *     key:    key
+ *     exactp: pointer to exact match flag
+ *
+ * Returns:
+ *     If an exact match found.
+ */
+static int
+__bt_snext(t, h, key, exactp)
+       BTREE *t;
+       PAGE *h;
+       const DBT *key;
+       int *exactp;
+{
+       EPG e;
+
+       /*
+        * Get the next page.  The key is either an exact
+        * match, or not as good as the one we already have.
+        */
+       if ((e.page = mpool_get(t->bt_mp, h->nextpg, 0)) == NULL)
+               return (0);
+       e.index = 0;
+       if (__bt_cmp(t, key, &e) == 0) {
+               mpool_put(t->bt_mp, h, 0);
+               t->bt_cur = e;
+               *exactp = 1;
+               return (1);
+       }
+       mpool_put(t->bt_mp, e.page, 0);
+       return (0);
+}
+
+/*
+ * __bt_sprev --
+ *     Check for an exact match before the key.
+ *
+ * Parameters:
+ *     t:      tree
+ *     h:      current page
+ *     key:    key
+ *     exactp: pointer to exact match flag
+ *
+ * Returns:
+ *     If an exact match found.
+ */
+static int
+__bt_sprev(t, h, key, exactp)
+       BTREE *t;
+       PAGE *h;
+       const DBT *key;
+       int *exactp;
+{
+       EPG e;
+
+       /*
+        * Get the previous page.  The key is either an exact
+        * match, or not as good as the one we already have.
+        */
+       if ((e.page = mpool_get(t->bt_mp, h->prevpg, 0)) == NULL)
+               return (0);
+       e.index = NEXTINDEX(e.page) - 1;
+       if (__bt_cmp(t, key, &e) == 0) {
+               mpool_put(t->bt_mp, h, 0);
+               t->bt_cur = e;
+               *exactp = 1;
+               return (1);
+       }
+       mpool_put(t->bt_mp, e.page, 0);
+       return (0);
+}
diff --git a/db1-ast/btree/bt_seq.c b/db1-ast/btree/bt_seq.c
new file mode 100755 (executable)
index 0000000..90f8960
--- /dev/null
@@ -0,0 +1,460 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *     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[] = "@(#)bt_seq.c   8.7 (Berkeley) 7/20/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <db.h>
+#include "btree.h"
+
+static int __bt_first __P((BTREE *, const DBT *, EPG *, int *));
+static int __bt_seqadv __P((BTREE *, EPG *, int));
+static int __bt_seqset __P((BTREE *, EPG *, DBT *, int));
+
+/*
+ * Sequential scan support.
+ *
+ * The tree can be scanned sequentially, starting from either end of the
+ * tree or from any specific key.  A scan request before any scanning is
+ * done is initialized as starting from the least node.
+ */
+
+/*
+ * __bt_seq --
+ *     Btree sequential scan interface.
+ *
+ * Parameters:
+ *     dbp:    pointer to access method
+ *     key:    key for positioning and return value
+ *     data:   data return value
+ *     flags:  R_CURSOR, R_FIRST, R_LAST, R_NEXT, R_PREV.
+ *
+ * Returns:
+ *     RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
+ */
+int
+__bt_seq(dbp, key, data, flags)
+       const DB *dbp;
+       DBT *key, *data;
+       u_int flags;
+{
+       BTREE *t;
+       EPG e;
+       int status;
+
+       t = dbp->internal;
+
+       /* Toss any page pinned across calls. */
+       if (t->bt_pinned != NULL) {
+               mpool_put(t->bt_mp, t->bt_pinned, 0);
+               t->bt_pinned = NULL;
+       }
+
+       /*
+        * If scan uninitialized as yet, or starting at a specific record, set
+        * the scan to a specific key.  Both __bt_seqset and __bt_seqadv pin
+        * the page the cursor references if they're successful.
+        */
+       switch (flags) {
+       case R_NEXT:
+       case R_PREV:
+               if (F_ISSET(&t->bt_cursor, CURS_INIT)) {
+                       status = __bt_seqadv(t, &e, flags);
+                       break;
+               }
+               /* FALLTHROUGH */
+       case R_FIRST:
+       case R_LAST:
+       case R_CURSOR:
+               status = __bt_seqset(t, &e, key, flags);
+               break;
+       default:
+               errno = EINVAL;
+               return (RET_ERROR);
+       }
+
+       if (status == RET_SUCCESS) {
+               __bt_setcur(t, e.page->pgno, e.index);
+
+               status =
+                   __bt_ret(t, &e, key, &t->bt_rkey, data, &t->bt_rdata, 0);
+
+               /*
+                * If the user is doing concurrent access, we copied the
+                * key/data, toss the page.
+                */
+               if (F_ISSET(t, B_DB_LOCK))
+                       mpool_put(t->bt_mp, e.page, 0);
+               else
+                       t->bt_pinned = e.page;
+       }
+       return (status);
+}
+
+/*
+ * __bt_seqset --
+ *     Set the sequential scan to a specific key.
+ *
+ * Parameters:
+ *     t:      tree
+ *     ep:     storage for returned key
+ *     key:    key for initial scan position
+ *     flags:  R_CURSOR, R_FIRST, R_LAST, R_NEXT, R_PREV
+ *
+ * Side effects:
+ *     Pins the page the cursor references.
+ *
+ * Returns:
+ *     RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
+ */
+static int
+__bt_seqset(t, ep, key, flags)
+       BTREE *t;
+       EPG *ep;
+       DBT *key;
+       int flags;
+{
+       PAGE *h;
+       pgno_t pg;
+       int exact;
+
+       /*
+        * Find the first, last or specific key in the tree and point the
+        * cursor at it.  The cursor may not be moved until a new key has
+        * been found.
+        */
+       switch (flags) {
+       case R_CURSOR:                          /* Keyed scan. */
+               /*
+                * Find the first instance of the key or the smallest key
+                * which is greater than or equal to the specified key.
+                */
+               if (key->data == NULL || key->size == 0) {
+                       errno = EINVAL;
+                       return (RET_ERROR);
+               }
+               return (__bt_first(t, key, ep, &exact));
+       case R_FIRST:                           /* First record. */
+       case R_NEXT:
+               /* Walk down the left-hand side of the tree. */
+               for (pg = P_ROOT;;) {
+                       if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
+                               return (RET_ERROR);
+
+                       /* Check for an empty tree. */
+                       if (NEXTINDEX(h) == 0) {
+                               mpool_put(t->bt_mp, h, 0);
+                               return (RET_SPECIAL);
+                       }
+
+                       if (h->flags & (P_BLEAF | P_RLEAF))
+                               break;
+                       pg = GETBINTERNAL(h, 0)->pgno;
+                       mpool_put(t->bt_mp, h, 0);
+               }
+               ep->page = h;
+               ep->index = 0;
+               break;
+       case R_LAST:                            /* Last record. */
+       case R_PREV:
+               /* Walk down the right-hand side of the tree. */
+               for (pg = P_ROOT;;) {
+                       if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
+                               return (RET_ERROR);
+
+                       /* Check for an empty tree. */
+                       if (NEXTINDEX(h) == 0) {
+                               mpool_put(t->bt_mp, h, 0);
+                               return (RET_SPECIAL);
+                       }
+
+                       if (h->flags & (P_BLEAF | P_RLEAF))
+                               break;
+                       pg = GETBINTERNAL(h, NEXTINDEX(h) - 1)->pgno;
+                       mpool_put(t->bt_mp, h, 0);
+               }
+
+               ep->page = h;
+               ep->index = NEXTINDEX(h) - 1;
+               break;
+       }
+       return (RET_SUCCESS);
+}
+
+/*
+ *     Advance the sequential scan.
+ *
+ * Parameters:
+ *     t:      tree
+ *     flags:  R_NEXT, R_PREV
+ *
+ * Side effects:
+ *     Pins the page the new key/data record is on.
+ *
+ * Returns:
+ *     RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
+ */
+static int
+       BTREE *t;
+       EPG *ep;
+       int flags;
+{
+       CURSOR *c;
+       PAGE *h;
+       indx_t index;
+       pgno_t pg;
+       int exact;
+
+       /*
+        * There are a couple of states that we can be in.  The cursor has
+        * been initialized by the time we get here, but that's all we know.
+        */
+       c = &t->bt_cursor;
+
+       /*
+        * The cursor was deleted where there weren't any duplicate records,
+        * so the key was saved.  Find out where that key would go in the
+        * current tree.  It doesn't matter if the returned key is an exact
+        * match or not -- if it's an exact match, the record was added after
+        * the delete so we can just return it.  If not, as long as there's
+        * a record there, return it.
+        */
+       if (F_ISSET(c, CURS_ACQUIRE))
+               return (__bt_first(t, &c->key, ep, &exact));
+
+       /* Get the page referenced by the cursor. */
+       if ((h = mpool_get(t->bt_mp, c->pg.pgno, 0)) == NULL)
+               return (RET_ERROR);
+
+       /*
+        * Find the next/previous record in the tree and point the cursor at
+        * it.  The cursor may not be moved until a new key has been found.
+        */
+       switch (flags) {
+       case R_NEXT:                    /* Next record. */
+               /*
+                * The cursor was deleted in duplicate records, and moved
+                * forward to a record that has yet to be returned.  Clear
+                * that flag, and return the record.
+                */
+               if (F_ISSET(c, CURS_AFTER))
+                       goto usecurrent;
+               index = c->pg.index;
+               if (++index == NEXTINDEX(h)) {
+                       pg = h->nextpg;
+                       mpool_put(t->bt_mp, h, 0);
+                       if (pg == P_INVALID)
+                               return (RET_SPECIAL);
+                       if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
+                               return (RET_ERROR);
+                       index = 0;
+               }
+               break;
+       case R_PREV:                    /* Previous record. */
+               /*
+                * The cursor was deleted in duplicate records, and moved
+                * backward to a record that has yet to be returned.  Clear
+                * that flag, and return the record.
+                */
+               if (F_ISSET(c, CURS_BEFORE)) {
+usecurrent:            F_CLR(c, CURS_AFTER | CURS_BEFORE);
+                       ep->page = h;
+                       ep->index = c->pg.index;
+                       return (RET_SUCCESS);
+               }
+               index = c->pg.index;
+               if (index == 0) {
+                       pg = h->prevpg;
+                       mpool_put(t->bt_mp, h, 0);
+                       if (pg == P_INVALID)
+                               return (RET_SPECIAL);
+                       if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
+                               return (RET_ERROR);
+                       index = NEXTINDEX(h) - 1;
+               } else
+                       --index;
+               break;
+       }
+
+       ep->page = h;
+       ep->index = index;
+       return (RET_SUCCESS);
+}
+
+/*
+ * __bt_first --
+ *     Find the first entry.
+ *
+ * Parameters:
+ *     t:      the tree
+ *    key:     the key
+ *  erval:     return EPG
+ * exactp:     pointer to exact match flag
+ *
+ * Returns:
+ *     The first entry in the tree greater than or equal to key,
+ *     or RET_SPECIAL if no such key exists.
+ */
+static int
+__bt_first(t, key, erval, exactp)
+       BTREE *t;
+       const DBT *key;
+       EPG *erval;
+       int *exactp;
+{
+       PAGE *h;
+       EPG *ep, save;
+       pgno_t pg;
+
+       /*
+        * Find any matching record; __bt_search pins the page.
+        *
+        * If it's an exact match and duplicates are possible, walk backwards
+        * in the tree until we find the first one.  Otherwise, make sure it's
+        * a valid key (__bt_search may return an index just past the end of a
+        * page) and return it.
+        */
+       if ((ep = __bt_search(t, key, exactp)) == NULL)
+               return (RET_SPECIAL);
+       if (*exactp) {
+               if (F_ISSET(t, B_NODUPS)) {
+                       *erval = *ep;
+                       return (RET_SUCCESS);
+               }
+
+               /*
+                * Walk backwards, as long as the entry matches and there are
+                * keys left in the tree.  Save a copy of each match in case
+                * we go too far.
+                */
+               save = *ep;
+               h = ep->page;
+               do {
+                       if (save.page->pgno != ep->page->pgno) {
+                               mpool_put(t->bt_mp, save.page, 0);
+                               save = *ep;
+                       } else
+                               save.index = ep->index;
+
+                       /*
+                        * Don't unpin the page the last (or original) match
+                        * was on, but make sure it's unpinned if an error
+                        * occurs.
+                        */
+                       if (ep->index == 0) {
+                               if (h->prevpg == P_INVALID)
+                                       break;
+                               if (h->pgno != save.page->pgno)
+                                       mpool_put(t->bt_mp, h, 0);
+                               if ((h = mpool_get(t->bt_mp,
+                                   h->prevpg, 0)) == NULL) {
+                                       if (h->pgno == save.page->pgno)
+                                               mpool_put(t->bt_mp,
+                                                   save.page, 0);
+                                       return (RET_ERROR);
+                               }
+                               ep->page = h;
+                               ep->index = NEXTINDEX(h);
+                       }
+                       --ep->index;
+               } while (__bt_cmp(t, key, ep) == 0);
+
+               /*
+                * Reach here with the last page that was looked at pinned,
+                * which may or may not be the same as the last (or original)
+                * match page.  If it's not useful, release it.
+                */
+               if (h->pgno != save.page->pgno)
+                       mpool_put(t->bt_mp, h, 0);
+
+               *erval = save;
+               return (RET_SUCCESS);
+       }
+
+       /* If at the end of a page, find the next entry. */
+       if (ep->index == NEXTINDEX(ep->page)) {
+               h = ep->page;
+               pg = h->nextpg;
+               mpool_put(t->bt_mp, h, 0);
+               if (pg == P_INVALID)
+                       return (RET_SPECIAL);
+               if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
+                       return (RET_ERROR);
+               ep->index = 0;
+               ep->page = h;
+       }
+       *erval = *ep;
+       return (RET_SUCCESS);
+}
+
+/*
+ * __bt_setcur --
+ *     Set the cursor to an entry in the tree.
+ *
+ * Parameters:
+ *     t:      the tree
+ *   pgno:     page number
+ *  index:     page index
+ */
+void
+__bt_setcur(t, pgno, index)
+       BTREE *t;
+       pgno_t pgno;
+       u_int index;
+{
+       /* Lose any already deleted key. */
+       if (t->bt_cursor.key.data != NULL) {
+               free(t->bt_cursor.key.data);
+               t->bt_cursor.key.size = 0;
+               t->bt_cursor.key.data = NULL;
+       }
+       F_CLR(&t->bt_cursor, CURS_ACQUIRE | CURS_AFTER | CURS_BEFORE);
+
+       /* Update the cursor. */
+       t->bt_cursor.pg.pgno = pgno;
+       t->bt_cursor.pg.index = index;
+       F_SET(&t->bt_cursor, CURS_INIT);
+}
diff --git a/db1-ast/btree/bt_split.c b/db1-ast/btree/bt_split.c
new file mode 100755 (executable)
index 0000000..4119ccb
--- /dev/null
@@ -0,0 +1,829 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *     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[] = "@(#)bt_split.c 8.9 (Berkeley) 7/26/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <db.h>
+#include "btree.h"
+
+static int      bt_broot __P((BTREE *, PAGE *, PAGE *, PAGE *));
+static PAGE    *bt_page
+                   __P((BTREE *, PAGE *, PAGE **, PAGE **, indx_t *, size_t));
+static int      bt_preserve __P((BTREE *, pgno_t));
+static PAGE    *bt_psplit
+                   __P((BTREE *, PAGE *, PAGE *, PAGE *, indx_t *, size_t));
+static PAGE    *bt_root
+                   __P((BTREE *, PAGE *, PAGE **, PAGE **, indx_t *, size_t));
+static int      bt_rroot __P((BTREE *, PAGE *, PAGE *, PAGE *));
+static recno_t  rec_total __P((PAGE *));
+
+#ifdef STATISTICS
+u_long bt_rootsplit, bt_split, bt_sortsplit, bt_pfxsaved;
+#endif
+
+/*
+ * __BT_SPLIT -- Split the tree.
+ *
+ * Parameters:
+ *     t:      tree
+ *     sp:     page to split
+ *     key:    key to insert
+ *     data:   data to insert
+ *     flags:  BIGKEY/BIGDATA flags
+ *     ilen:   insert length
+ *     skip:   index to leave open
+ *
+ * Returns:
+ *     RET_ERROR, RET_SUCCESS
+ */
+int
+__bt_split(t, sp, key, data, flags, ilen, argskip)
+       BTREE *t;
+       PAGE *sp;
+       const DBT *key, *data;
+       int flags;
+       size_t ilen;
+       u_int32_t argskip;
+{
+       BINTERNAL *bi;
+       BLEAF *bl, *tbl;
+       DBT a, b;
+       EPGNO *parent;
+       PAGE *h, *l, *r, *lchild, *rchild;
+       indx_t nxtindex;
+       u_int16_t skip;
+       u_int32_t n, nbytes, nksize;
+       int parentsplit;
+       char *dest;
+
+       /*
+        * Split the page into two pages, l and r.  The split routines return
+        * a pointer to the page into which the key should be inserted and with
+        * skip set to the offset which should be used.  Additionally, l and r
+        * are pinned.
+        */
+       skip = argskip;
+       h = sp->pgno == P_ROOT ?
+           bt_root(t, sp, &l, &r, &skip, ilen) :
+           bt_page(t, sp, &l, &r, &skip, ilen);
+       if (h == NULL)
+               return (RET_ERROR);
+
+       /*
+        * Insert the new key/data pair into the leaf page.  (Key inserts
+        * always cause a leaf page to split first.)
+        */
+       h->linp[skip] = h->upper -= ilen;
+       dest = (char *)h + h->upper;
+       if (F_ISSET(t, R_RECNO))
+               WR_RLEAF(dest, data, flags)
+       else
+               WR_BLEAF(dest, key, data, flags)
+
+       /* If the root page was split, make it look right. */
+       if (sp->pgno == P_ROOT &&
+           (F_ISSET(t, R_RECNO) ?
+           bt_rroot(t, sp, l, r) : bt_broot(t, sp, l, r)) == RET_ERROR)
+               goto err2;
+
+       /*
+        * Now we walk the parent page stack -- a LIFO stack of the pages that
+        * were traversed when we searched for the page that split.  Each stack
+        * entry is a page number and a page index offset.  The offset is for
+        * the page traversed on the search.  We've just split a page, so we
+        * have to insert a new key into the parent page.
+        *
+        * If the insert into the parent page causes it to split, may have to
+        * continue splitting all the way up the tree.  We stop if the root
+        * splits or the page inserted into didn't have to split to hold the
+        * new key.  Some algorithms replace the key for the old page as well
+        * as the new page.  We don't, as there's no reason to believe that the
+        * first key on the old page is any better than the key we have, and,
+        * in the case of a key being placed at index 0 causing the split, the
+        * key is unavailable.
+        *
+        * There are a maximum of 5 pages pinned at any time.  We keep the left
+        * and right pages pinned while working on the parent.   The 5 are the
+        * two children, left parent and right parent (when the parent splits)
+        * and the root page or the overflow key page when calling bt_preserve.
+        * This code must make sure that all pins are released other than the
+        * root page or overflow page which is unlocked elsewhere.
+        */
+       while ((parent = BT_POP(t)) != NULL) {
+               lchild = l;
+               rchild = r;
+
+               /* Get the parent page. */
+               if ((h = mpool_get(t->bt_mp, parent->pgno, 0)) == NULL)
+                       goto err2;
+
+               /*
+                * The new key goes ONE AFTER the index, because the split
+                * was to the right.
+                */
+               skip = parent->index + 1;
+
+               /*
+                * Calculate the space needed on the parent page.
+                *
+                * Prefix trees: space hack when inserting into BINTERNAL
+                * pages.  Retain only what's needed to distinguish between
+                * the new entry and the LAST entry on the page to its left.
+                * If the keys compare equal, retain the entire key.  Note,
+                * we don't touch overflow keys, and the entire key must be
+                * retained for the next-to-left most key on the leftmost
+                * page of each level, or the search will fail.  Applicable
+                * ONLY to internal pages that have leaf pages as children.
+                * Further reduction of the key between pairs of internal
+                * pages loses too much information.
+                */
+               switch (rchild->flags & P_TYPE) {
+               case P_BINTERNAL:
+                       bi = GETBINTERNAL(rchild, 0);
+                       nbytes = NBINTERNAL(bi->ksize);
+                       break;
+               case P_BLEAF:
+                       bl = GETBLEAF(rchild, 0);
+                       nbytes = NBINTERNAL(bl->ksize);
+                       if (t->bt_pfx && !(bl->flags & P_BIGKEY) &&
+                           (h->prevpg != P_INVALID || skip > 1)) {
+                               tbl = GETBLEAF(lchild, NEXTINDEX(lchild) - 1);
+                               a.size = tbl->ksize;
+                               a.data = tbl->bytes;
+                               b.size = bl->ksize;
+                               b.data = bl->bytes;
+                               nksize = t->bt_pfx(&a, &b);
+                               n = NBINTERNAL(nksize);
+                               if (n < nbytes) {
+#ifdef STATISTICS
+                                       bt_pfxsaved += nbytes - n;
+#endif
+                                       nbytes = n;
+                               } else
+                                       nksize = 0;
+                       } else
+                               nksize = 0;
+                       break;
+               case P_RINTERNAL:
+               case P_RLEAF:
+                       nbytes = NRINTERNAL;
+                       break;
+               default:
+                       abort();
+               }
+
+               /* Split the parent page if necessary or shift the indices. */
+               if ((u_int32_t) (h->upper - h->lower)
+                   < nbytes + sizeof(indx_t)) {
+                       sp = h;
+                       h = h->pgno == P_ROOT ?
+                           bt_root(t, h, &l, &r, &skip, nbytes) :
+                           bt_page(t, h, &l, &r, &skip, nbytes);
+                       if (h == NULL)
+                               goto err1;
+                       parentsplit = 1;
+               } else {
+                       if (skip < (nxtindex = NEXTINDEX(h)))
+                               memmove(h->linp + skip + 1, h->linp + skip,
+                                   (nxtindex - skip) * sizeof(indx_t));
+                       h->lower += sizeof(indx_t);
+                       parentsplit = 0;
+               }
+
+               /* Insert the key into the parent page. */
+               switch (rchild->flags & P_TYPE) {
+               case P_BINTERNAL:
+                       h->linp[skip] = h->upper -= nbytes;
+                       dest = (char *)h + h->linp[skip];
+                       memmove(dest, bi, nbytes);
+                       ((BINTERNAL *)dest)->pgno = rchild->pgno;
+                       break;
+               case P_BLEAF:
+                       h->linp[skip] = h->upper -= nbytes;
+                       dest = (char *)h + h->linp[skip];
+                       WR_BINTERNAL(dest, nksize ? nksize : bl->ksize,
+                           rchild->pgno, bl->flags & P_BIGKEY);
+                       memmove(dest, bl->bytes, nksize ? nksize : bl->ksize);
+                       if (bl->flags & P_BIGKEY &&
+                           bt_preserve(t, *(pgno_t *)bl->bytes) == RET_ERROR)
+                               goto err1;
+                       break;
+               case P_RINTERNAL:
+                       /*
+                        * Update the left page count.  If split
+                        * added at index 0, fix the correct page.
+                        */
+                       if (skip > 0)
+                               dest = (char *)h + h->linp[skip - 1];
+                       else
+                               dest = (char *)l + l->linp[NEXTINDEX(l) - 1];
+                       ((RINTERNAL *)dest)->nrecs = rec_total(lchild);
+                       ((RINTERNAL *)dest)->pgno = lchild->pgno;
+
+                       /* Update the right page count. */
+                       h->linp[skip] = h->upper -= nbytes;
+                       dest = (char *)h + h->linp[skip];
+                       ((RINTERNAL *)dest)->nrecs = rec_total(rchild);
+                       ((RINTERNAL *)dest)->pgno = rchild->pgno;
+                       break;
+               case P_RLEAF:
+                       /*
+                        * Update the left page count.  If split
+                        * added at index 0, fix the correct page.
+                        */
+                       if (skip > 0)
+                               dest = (char *)h + h->linp[skip - 1];
+                       else
+                               dest = (char *)l + l->linp[NEXTINDEX(l) - 1];
+                       ((RINTERNAL *)dest)->nrecs = NEXTINDEX(lchild);
+                       ((RINTERNAL *)dest)->pgno = lchild->pgno;
+
+                       /* Update the right page count. */
+                       h->linp[skip] = h->upper -= nbytes;
+                       dest = (char *)h + h->linp[skip];
+                       ((RINTERNAL *)dest)->nrecs = NEXTINDEX(rchild);
+                       ((RINTERNAL *)dest)->pgno = rchild->pgno;
+                       break;
+               default:
+                       abort();
+               }
+
+               /* Unpin the held pages. */
+               if (!parentsplit) {
+                       mpool_put(t->bt_mp, h, MPOOL_DIRTY);
+                       break;
+               }
+
+               /* If the root page was split, make it look right. */
+               if (sp->pgno == P_ROOT &&
+                   (F_ISSET(t, R_RECNO) ?
+                   bt_rroot(t, sp, l, r) : bt_broot(t, sp, l, r)) == RET_ERROR)
+                       goto err1;
+
+               mpool_put(t->bt_mp, lchild, MPOOL_DIRTY);
+               mpool_put(t->bt_mp, rchild, MPOOL_DIRTY);
+       }
+
+       /* Unpin the held pages. */
+       mpool_put(t->bt_mp, l, MPOOL_DIRTY);
+       mpool_put(t->bt_mp, r, MPOOL_DIRTY);
+
+       /* Clear any pages left on the stack. */
+       return (RET_SUCCESS);
+
+       /*
+        * If something fails in the above loop we were already walking back
+        * up the tree and the tree is now inconsistent.  Nothing much we can
+        * do about it but release any memory we're holding.
+        */
+err1:  mpool_put(t->bt_mp, lchild, MPOOL_DIRTY);
+       mpool_put(t->bt_mp, rchild, MPOOL_DIRTY);
+
+err2:  mpool_put(t->bt_mp, l, 0);
+       mpool_put(t->bt_mp, r, 0);
+       __dbpanic(t->bt_dbp);
+       return (RET_ERROR);
+}
+
+/*
+ * BT_PAGE -- Split a non-root page of a btree.
+ *
+ * Parameters:
+ *     t:      tree
+ *     h:      root page
+ *     lp:     pointer to left page pointer
+ *     rp:     pointer to right page pointer
+ *     skip:   pointer to index to leave open
+ *     ilen:   insert length
+ *
+ * Returns:
+ *     Pointer to page in which to insert or NULL on error.
+ */
+static PAGE *
+bt_page(t, h, lp, rp, skip, ilen)
+       BTREE *t;
+       PAGE *h, **lp, **rp;
+       indx_t *skip;
+       size_t ilen;
+{
+       PAGE *l, *r, *tp;
+       pgno_t npg;
+
+#ifdef STATISTICS
+       ++bt_split;
+#endif
+       /* Put the new right page for the split into place. */
+       if ((r = __bt_new(t, &npg)) == NULL)
+               return (NULL);
+       r->pgno = npg;
+       r->lower = BTDATAOFF;
+       r->upper = t->bt_psize;
+       r->nextpg = h->nextpg;
+       r->prevpg = h->pgno;
+       r->flags = h->flags & P_TYPE;
+
+       /*
+        * If we're splitting the last page on a level because we're appending
+        * a key to it (skip is NEXTINDEX()), it's likely that the data is
+        * sorted.  Adding an empty page on the side of the level is less work
+        * and can push the fill factor much higher than normal.  If we're
+        * wrong it's no big deal, we'll just do the split the right way next
+        * time.  It may look like it's equally easy to do a similar hack for
+        * reverse sorted data, that is, split the tree left, but it's not.
+        * Don't even try.
+        */
+       if (h->nextpg == P_INVALID && *skip == NEXTINDEX(h)) {
+#ifdef STATISTICS
+               ++bt_sortsplit;
+#endif
+               h->nextpg = r->pgno;
+               r->lower = BTDATAOFF + sizeof(indx_t);
+               *skip = 0;
+               *lp = h;
+               *rp = r;
+               return (r);
+       }
+
+       /* Put the new left page for the split into place. */
+       if ((l = (PAGE *)malloc(t->bt_psize)) == NULL) {
+               mpool_put(t->bt_mp, r, 0);
+               return (NULL);
+       }
+#ifdef PURIFY
+       memset(l, 0xff, t->bt_psize);
+#endif
+       l->pgno = h->pgno;
+       l->nextpg = r->pgno;
+       l->prevpg = h->prevpg;
+       l->lower = BTDATAOFF;
+       l->upper = t->bt_psize;
+       l->flags = h->flags & P_TYPE;
+
+       /* Fix up the previous pointer of the page after the split page. */
+       if (h->nextpg != P_INVALID) {
+               if ((tp = mpool_get(t->bt_mp, h->nextpg, 0)) == NULL) {
+                       free(l);
+                       /* XXX mpool_free(t->bt_mp, r->pgno); */
+                       return (NULL);
+               }
+               tp->prevpg = r->pgno;
+               mpool_put(t->bt_mp, tp, MPOOL_DIRTY);
+       }
+
+       /*
+        * Split right.  The key/data pairs aren't sorted in the btree page so
+        * it's simpler to copy the data from the split page onto two new pages
+        * instead of copying half the data to the right page and compacting
+        * the left page in place.  Since the left page can't change, we have
+        * to swap the original and the allocated left page after the split.
+        */
+       tp = bt_psplit(t, h, l, r, skip, ilen);
+
+       /* Move the new left page onto the old left page. */
+       memmove(h, l, t->bt_psize);
+       if (tp == l)
+               tp = h;
+       free(l);
+
+       *lp = h;
+       *rp = r;
+       return (tp);
+}
+
+/*
+ * BT_ROOT -- Split the root page of a btree.
+ *
+ * Parameters:
+ *     t:      tree
+ *     h:      root page
+ *     lp:     pointer to left page pointer
+ *     rp:     pointer to right page pointer
+ *     skip:   pointer to index to leave open
+ *     ilen:   insert length
+ *
+ * Returns:
+ *     Pointer to page in which to insert or NULL on error.
+ */
+static PAGE *
+bt_root(t, h, lp, rp, skip, ilen)
+       BTREE *t;
+       PAGE *h, **lp, **rp;
+       indx_t *skip;
+       size_t ilen;
+{
+       PAGE *l, *r, *tp;
+       pgno_t lnpg, rnpg;
+
+#ifdef STATISTICS
+       ++bt_split;
+       ++bt_rootsplit;
+#endif
+       /* Put the new left and right pages for the split into place. */
+       if ((l = __bt_new(t, &lnpg)) == NULL ||
+           (r = __bt_new(t, &rnpg)) == NULL)
+               return (NULL);
+       l->pgno = lnpg;
+       r->pgno = rnpg;
+       l->nextpg = r->pgno;
+       r->prevpg = l->pgno;
+       l->prevpg = r->nextpg = P_INVALID;
+       l->lower = r->lower = BTDATAOFF;
+       l->upper = r->upper = t->bt_psize;
+       l->flags = r->flags = h->flags & P_TYPE;
+
+       /* Split the root page. */
+       tp = bt_psplit(t, h, l, r, skip, ilen);
+
+       *lp = l;
+       *rp = r;
+       return (tp);
+}
+
+/*
+ * BT_RROOT -- Fix up the recno root page after it has been split.
+ *
+ * Parameters:
+ *     t:      tree
+ *     h:      root page
+ *     l:      left page
+ *     r:      right page
+ *
+ * Returns:
+ *     RET_ERROR, RET_SUCCESS
+ */
+static int
+bt_rroot(t, h, l, r)
+       BTREE *t;
+       PAGE *h, *l, *r;
+{
+       char *dest;
+
+       /* Insert the left and right keys, set the header information. */
+       h->linp = h->upper = t->bt_psize - NRINTERNAL;
+       dest = (char *)h + h->upper;
+       WR_RINTERNAL(dest,
+           l->flags & P_RLEAF ? NEXTINDEX(l) : rec_total(l), l->pgno);
+
+       h->linp = h->upper -= NRINTERNAL;
+       dest = (char *)h + h->upper;
+       WR_RINTERNAL(dest,
+           r->flags & P_RLEAF ? NEXTINDEX(r) : rec_total(r), r->pgno);
+
+       h->lower = BTDATAOFF + 2 * sizeof(indx_t);
+
+       /* Unpin the root page, set to recno internal page. */
+       h->flags &= ~P_TYPE;
+       h->flags |= P_RINTERNAL;
+       mpool_put(t->bt_mp, h, MPOOL_DIRTY);
+
+       return (RET_SUCCESS);
+}
+
+/*
+ * BT_BROOT -- Fix up the btree root page after it has been split.
+ *
+ * Parameters:
+ *     t:      tree
+ *     h:      root page
+ *     l:      left page
+ *     r:      right page
+ *
+ * Returns:
+ *     RET_ERROR, RET_SUCCESS
+ */
+static int
+bt_broot(t, h, l, r)
+       BTREE *t;
+       PAGE *h, *l, *r;
+{
+       BINTERNAL *bi;
+       BLEAF *bl;
+       u_int32_t nbytes;
+       char *dest;
+
+       /*
+        * If the root page was a leaf page, change it into an internal page.
+        * We copy the key we split on (but not the key's data, in the case of
+        * a leaf page) to the new root page.
+        *
+        * The btree comparison code guarantees that the left-most key on any
+        * level of the tree is never used, so it doesn't need to be filled in.
+        */
+       nbytes = NBINTERNAL(0);
+       h->linp = h->upper = t->bt_psize - nbytes;
+       dest = (char *)h + h->upper;
+       WR_BINTERNAL(dest, 0, l->pgno, 0);
+
+       switch (h->flags & P_TYPE) {
+       case P_BLEAF:
+               bl = GETBLEAF(r, 0);
+               nbytes = NBINTERNAL(bl->ksize);
+               h->linp = h->upper -= nbytes;
+               dest = (char *)h + h->upper;
+               WR_BINTERNAL(dest, bl->ksize, r->pgno, 0);
+               memmove(dest, bl->bytes, bl->ksize);
+
+               /*
+                * If the key is on an overflow page, mark the overflow chain
+                * so it isn't deleted when the leaf copy of the key is deleted.
+                */
+               if (bl->flags & P_BIGKEY &&
+                   bt_preserve(t, *(pgno_t *)bl->bytes) == RET_ERROR)
+                       return (RET_ERROR);
+               break;
+       case P_BINTERNAL:
+               bi = GETBINTERNAL(r, 0);
+               nbytes = NBINTERNAL(bi->ksize);
+               h->linp = h->upper -= nbytes;
+               dest = (char *)h + h->upper;
+               memmove(dest, bi, nbytes);
+               ((BINTERNAL *)dest)->pgno = r->pgno;
+               break;
+       default:
+               abort();
+       }
+
+       /* There are two keys on the page. */
+       h->lower = BTDATAOFF + 2 * sizeof(indx_t);
+
+       /* Unpin the root page, set to btree internal page. */
+       h->flags &= ~P_TYPE;
+       h->flags |= P_BINTERNAL;
+       mpool_put(t->bt_mp, h, MPOOL_DIRTY);
+
+       return (RET_SUCCESS);
+}
+
+/*
+ * BT_PSPLIT -- Do the real work of splitting the page.
+ *
+ * Parameters:
+ *     t:      tree
+ *     h:      page to be split
+ *     l:      page to put lower half of data
+ *     r:      page to put upper half of data
+ *     pskip:  pointer to index to leave open
+ *     ilen:   insert length
+ *
+ * Returns:
+ *     Pointer to page in which to insert.
+ */
+static PAGE *
+bt_psplit(t, h, l, r, pskip, ilen)
+       BTREE *t;
+       PAGE *h, *l, *r;
+       indx_t *pskip;
+       size_t ilen;
+{
+       BINTERNAL *bi;
+       BLEAF *bl;
+       CURSOR *c;
+       RLEAF *rl;
+       PAGE *rval;
+       void *src;
+       indx_t full, half, nxt, off, skip, top, used;
+       u_int32_t nbytes;
+       int bigkeycnt, isbigkey;
+
+       /*
+        * Split the data to the left and right pages.  Leave the skip index
+        * open.  Additionally, make some effort not to split on an overflow
+        * key.  This makes internal page processing faster and can save
+        * space as overflow keys used by internal pages are never deleted.
+        */
+       bigkeycnt = 0;
+       skip = *pskip;
+       full = t->bt_psize - BTDATAOFF;
+       half = full / 2;
+       used = 0;
+       for (nxt = off = 0, top = NEXTINDEX(h); nxt < top; ++off) {
+               if (skip == off) {
+                       nbytes = ilen;
+                       isbigkey = 0;           /* XXX: not really known. */
+               } else
+                       switch (h->flags & P_TYPE) {
+                       case P_BINTERNAL:
+                               src = bi = GETBINTERNAL(h, nxt);
+                               nbytes = NBINTERNAL(bi->ksize);
+                               isbigkey = bi->flags & P_BIGKEY;
+                               break;
+                       case P_BLEAF:
+                               src = bl = GETBLEAF(h, nxt);
+                               nbytes = NBLEAF(bl);
+                               isbigkey = bl->flags & P_BIGKEY;
+                               break;
+                       case P_RINTERNAL:
+                               src = GETRINTERNAL(h, nxt);
+                               nbytes = NRINTERNAL;
+                               isbigkey = 0;
+                               break;
+                       case P_RLEAF:
+                               src = rl = GETRLEAF(h, nxt);
+                               nbytes = NRLEAF(rl);
+                               isbigkey = 0;
+                               break;
+                       default:
+                               abort();
+                       }
+
+               /*
+                * If the key/data pairs are substantial fractions of the max
+                * possible size for the page, it's possible to get situations
+                * where we decide to try and copy too much onto the left page.
+                * Make sure that doesn't happen.
+                */
+               if ((skip <= off && used + nbytes + sizeof(indx_t) >= full)
+                   || nxt == top - 1) {
+                       --off;
+                       break;
+               }
+
+               /* Copy the key/data pair, if not the skipped index. */
+               if (skip != off) {
+                       ++nxt;
+
+                       l->linp[off] = l->upper -= nbytes;
+                       memmove((char *)l + l->upper, src, nbytes);
+               }
+
+               used += nbytes + sizeof(indx_t);
+               if (used >= half) {
+                       if (!isbigkey || bigkeycnt == 3)
+                               break;
+                       else
+                               ++bigkeycnt;
+               }
+       }
+
+       /*
+        * Off is the last offset that's valid for the left page.
+        * Nxt is the first offset to be placed on the right page.
+        */
+       l->lower += (off + 1) * sizeof(indx_t);
+
+       /*
+        * If splitting the page that the cursor was on, the cursor has to be
+        * adjusted to point to the same record as before the split.  If the
+        * cursor is at or past the skipped slot, the cursor is incremented by
+        * one.  If the cursor is on the right page, it is decremented by the
+        * number of records split to the left page.
+        */
+       c = &t->bt_cursor;
+       if (F_ISSET(c, CURS_INIT) && c->pg.pgno == h->pgno) {
+               if (c->pg.index >= skip)
+                       ++c->pg.index;
+               if (c->pg.index < nxt)                  /* Left page. */
+                       c->pg.pgno = l->pgno;
+               else {                                  /* Right page. */
+                       c->pg.pgno = r->pgno;
+                       c->pg.index -= nxt;
+               }
+       }
+
+       /*
+        * If the skipped index was on the left page, just return that page.
+        * Otherwise, adjust the skip index to reflect the new position on
+        * the right page.
+        */
+       if (skip <= off) {
+               skip = 0;
+               rval = l;
+       } else {
+               rval = r;
+               *pskip -= nxt;
+       }
+
+       for (off = 0; nxt < top; ++off) {
+               if (skip == nxt) {
+                       ++off;
+                       skip = 0;
+               }
+               switch (h->flags & P_TYPE) {
+               case P_BINTERNAL:
+                       src = bi = GETBINTERNAL(h, nxt);
+                       nbytes = NBINTERNAL(bi->ksize);
+                       break;
+               case P_BLEAF:
+                       src = bl = GETBLEAF(h, nxt);
+                       nbytes = NBLEAF(bl);
+                       break;
+               case P_RINTERNAL:
+                       src = GETRINTERNAL(h, nxt);
+                       nbytes = NRINTERNAL;
+                       break;
+               case P_RLEAF:
+                       src = rl = GETRLEAF(h, nxt);
+                       nbytes = NRLEAF(rl);
+                       break;
+               default:
+                       abort();
+               }
+               ++nxt;
+               r->linp[off] = r->upper -= nbytes;
+               memmove((char *)r + r->upper, src, nbytes);
+       }
+       r->lower += off * sizeof(indx_t);
+
+       /* If the key is being appended to the page, adjust the index. */
+       if (skip == top)
+               r->lower += sizeof(indx_t);
+
+       return (rval);
+}
+
+/*
+ * BT_PRESERVE -- Mark a chain of pages as used by an internal node.
+ *
+ * Chains of indirect blocks pointed to by leaf nodes get reclaimed when the
+ * record that references them gets deleted.  Chains pointed to by internal
+ * pages never get deleted.  This routine marks a chain as pointed to by an
+ * internal page.
+ *
+ * Parameters:
+ *     t:      tree
+ *     pg:     page number of first page in the chain.
+ *
+ * Returns:
+ *     RET_SUCCESS, RET_ERROR.
+ */
+static int
+bt_preserve(t, pg)
+       BTREE *t;
+       pgno_t pg;
+{
+       PAGE *h;
+
+       if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
+               return (RET_ERROR);
+       h->flags |= P_PRESERVE;
+       mpool_put(t->bt_mp, h, MPOOL_DIRTY);
+       return (RET_SUCCESS);
+}
+
+/*
+ * REC_TOTAL -- Return the number of recno entries below a page.
+ *
+ * Parameters:
+ *     h:      page
+ *
+ * Returns:
+ *     The number of recno entries below a page.
+ *
+ * XXX
+ * These values could be set by the bt_psplit routine.  The problem is that the
+ * entry has to be popped off of the stack etc. or the values have to be passed
+ * all the way back to bt_split/bt_rroot and it's not very clean.
+ */
+static recno_t
+rec_total(h)
+       PAGE *h;
+{
+       recno_t recs;
+       indx_t nxt, top;
+
+       for (recs = 0, nxt = 0, top = NEXTINDEX(h); nxt < top; ++nxt)
+               recs += GETRINTERNAL(h, nxt)->nrecs;
+       return (recs);
+}
diff --git a/db1-ast/btree/bt_utils.c b/db1-ast/btree/bt_utils.c
new file mode 100755 (executable)
index 0000000..1416c78
--- /dev/null
@@ -0,0 +1,260 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *     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[] = "@(#)bt_utils.c 8.8 (Berkeley) 7/20/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/param.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <db.h>
+#include "btree.h"
+
+/*
+ * __bt_ret --
+ *     Build return key/data pair.
+ *
+ * Parameters:
+ *     t:      tree
+ *     e:      key/data pair to be returned
+ *     key:    user's key structure (NULL if not to be filled in)
+ *     rkey:   memory area to hold key
+ *     data:   user's data structure (NULL if not to be filled in)
+ *     rdata:  memory area to hold data
+ *       copy: always copy the key/data item
+ *
+ * Returns:
+ *     RET_SUCCESS, RET_ERROR.
+ */
+int
+__bt_ret(t, e, key, rkey, data, rdata, copy)
+       BTREE *t;
+       EPG *e;
+       DBT *key, *rkey, *data, *rdata;
+       int copy;
+{
+       BLEAF *bl;
+       void *p;
+
+       bl = GETBLEAF(e->page, e->index);
+
+       /*
+        * We must copy big keys/data to make them contiguous.  Otherwise,
+        * leave the page pinned and don't copy unless the user specified
+        * concurrent access.
+        */
+       if (key == NULL)
+               goto dataonly;
+
+       if (bl->flags & P_BIGKEY) {
+               if (__ovfl_get(t, bl->bytes,
+                   &key->size, &rkey->data, &rkey->size))
+                       return (RET_ERROR);
+               key->data = rkey->data;
+       } else if (copy || F_ISSET(t, B_DB_LOCK)) {
+               if (bl->ksize > rkey->size) {
+                       p = (void *)(rkey->data == NULL ?
+                           malloc(bl->ksize) : realloc(rkey->data, bl->ksize));
+                       if (p == NULL)
+                               return (RET_ERROR);
+                       rkey->data = p;
+                       rkey->size = bl->ksize;
+               }
+               memmove(rkey->data, bl->bytes, bl->ksize);
+               key->size = bl->ksize;
+               key->data = rkey->data;
+       } else {
+               key->size = bl->ksize;
+               key->data = bl->bytes;
+       }
+
+dataonly:
+       if (data == NULL)
+               return (RET_SUCCESS);
+
+       if (bl->flags & P_BIGDATA) {
+               if (__ovfl_get(t, bl->bytes + bl->ksize,
+                   &data->size, &rdata->data, &rdata->size))
+                       return (RET_ERROR);
+               data->data = rdata->data;
+       } else if (copy || F_ISSET(t, B_DB_LOCK)) {
+               /* Use +1 in case the first record retrieved is 0 length. */
+               if (bl->dsize + 1 > rdata->size) {
+                       p = (void *)(rdata->data == NULL ?
+                           malloc(bl->dsize + 1) :
+                           realloc(rdata->data, bl->dsize + 1));
+                       if (p == NULL)
+                               return (RET_ERROR);
+                       rdata->data = p;
+                       rdata->size = bl->dsize + 1;
+               }
+               memmove(rdata->data, bl->bytes + bl->ksize, bl->dsize);
+               data->size = bl->dsize;
+               data->data = rdata->data;
+       } else {
+               data->size = bl->dsize;
+               data->data = bl->bytes + bl->ksize;
+       }
+
+       return (RET_SUCCESS);
+}
+
+/*
+ * __BT_CMP -- Compare a key to a given record.
+ *
+ * Parameters:
+ *     t:      tree
+ *     k1:     DBT pointer of first arg to comparison
+ *     e:      pointer to EPG for comparison
+ *
+ * Returns:
+ *     < 0 if k1 is < record
+ *     = 0 if k1 is = record
+ *     > 0 if k1 is > record
+ */
+int
+__bt_cmp(t, k1, e)
+       BTREE *t;
+       const DBT *k1;
+       EPG *e;
+{
+       BINTERNAL *bi;
+       BLEAF *bl;
+       DBT k2;
+       PAGE *h;
+       void *bigkey;
+
+       /*
+        * The left-most key on internal pages, at any level of the tree, is
+        * guaranteed by the following code to be less than any user key.
+        * This saves us from having to update the leftmost key on an internal
+        * page when the user inserts a new key in the tree smaller than
+        * anything we've yet seen.
+        */
+       h = e->page;
+       if (e->index == 0 && h->prevpg == P_INVALID && !(h->flags & P_BLEAF))
+               return (1);
+
+       bigkey = NULL;
+       if (h->flags & P_BLEAF) {
+               bl = GETBLEAF(h, e->index);
+               if (bl->flags & P_BIGKEY)
+                       bigkey = bl->bytes;
+               else {
+                       k2.data = bl->bytes;
+                       k2.size = bl->ksize;
+               }
+       } else {
+               bi = GETBINTERNAL(h, e->index);
+               if (bi->flags & P_BIGKEY)
+                       bigkey = bi->bytes;
+               else {
+                       k2.data = bi->bytes;
+                       k2.size = bi->ksize;
+               }
+       }
+
+       if (bigkey) {
+               if (__ovfl_get(t, bigkey,
+                   &k2.size, &t->bt_rdata.data, &t->bt_rdata.size))
+                       return (RET_ERROR);
+               k2.data = t->bt_rdata.data;
+       }
+       return ((*t->bt_cmp)(k1, &k2));
+}
+
+/*
+ * __BT_DEFCMP -- Default comparison routine.
+ *
+ * Parameters:
+ *     a:      DBT #1
+ *     b:      DBT #2
+ *
+ * Returns:
+ *     < 0 if a is < b
+ *     = 0 if a is = b
+ *     > 0 if a is > b
+ */
+int
+__bt_defcmp(a, b)
+       const DBT *a, *b;
+{
+       register size_t len;
+       register u_char *p1, *p2;
+
+       /*
+        * XXX
+        * If a size_t doesn't fit in an int, this routine can lose.
+        * What we need is a integral type which is guaranteed to be
+        * larger than a size_t, and there is no such thing.
+        */
+       len = MIN(a->size, b->size);
+       for (p1 = a->data, p2 = b->data; len--; ++p1, ++p2)
+               if (*p1 != *p2)
+                       return ((int)*p1 - (int)*p2);
+       return ((int)a->size - (int)b->size);
+}
+
+/*
+ * __BT_DEFPFX -- Default prefix routine.
+ *
+ * Parameters:
+ *     a:      DBT #1
+ *     b:      DBT #2
+ *
+ * Returns:
+ *     Number of bytes needed to distinguish b from a.
+ */
+size_t
+__bt_defpfx(a, b)
+       const DBT *a, *b;
+{
+       register u_char *p1, *p2;
+       register size_t cnt, len;
+
+       cnt = 1;
+       len = MIN(a->size, b->size);
+       for (p1 = a->data, p2 = b->data; len--; ++p1, ++p2, ++cnt)
+               if (*p1 != *p2)
+                       return (cnt);
+
+       /* a->size must be <= b->size, or they wouldn't be in this order. */
+       return (a->size < b->size ? a->size + 1 : a->size);
+}
diff --git a/db1-ast/btree/btree.h b/db1-ast/btree/btree.h
new file mode 100755 (executable)
index 0000000..1f4a9ec
--- /dev/null
@@ -0,0 +1,391 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ *     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.
+ *
+ *     @(#)btree.h     8.11 (Berkeley) 8/17/94
+ */
+
+/* Macros to set/clear/test flags. */
+#define        F_SET(p, f)     (p)->flags |= (f)
+#define        F_CLR(p, f)     (p)->flags &= ~(f)
+#define        F_ISSET(p, f)   ((p)->flags & (f))
+
+#include <mpool.h>
+
+#define mpool_open __mpool_open
+#define mpool_filter __mpool_filter
+#define mpool_new __mpool_new
+#define mpool_get __mpool_get
+#define mpool_put __mpool_put
+#define mpool_sync __mpool_sync
+#define mpool_close __mpool_close
+
+#define        DEFMINKEYPAGE   (2)             /* Minimum keys per page */
+#define        MINCACHE        (5)             /* Minimum cached pages */
+#define        MINPSIZE        (512)           /* Minimum page size */
+
+/*
+ * Page 0 of a btree file contains a copy of the meta-data.  This page is also
+ * used as an out-of-band page, i.e. page pointers that point to nowhere point
+ * to page 0.  Page 1 is the root of the btree.
+ */
+#define        P_INVALID        0              /* Invalid tree page number. */
+#define        P_META           0              /* Tree metadata page number. */
+#define        P_ROOT           1              /* Tree root page number. */
+
+/*
+ * There are five page layouts in the btree: btree internal pages (BINTERNAL),
+ * btree leaf pages (BLEAF), recno internal pages (RINTERNAL), recno leaf pages
+ * (RLEAF) and overflow pages.  All five page types have a page header (PAGE).
+ * This implementation requires that values within structures NOT be padded.
+ * (ANSI C permits random padding.)  If your compiler pads randomly you'll have
+ * to do some work to get this package to run.
+ */
+typedef struct _page {
+       pgno_t  pgno;                   /* this page's page number */
+       pgno_t  prevpg;                 /* left sibling */
+       pgno_t  nextpg;                 /* right sibling */
+
+#define        P_BINTERNAL     0x01            /* btree internal page */
+#define        P_BLEAF         0x02            /* leaf page */
+#define        P_OVERFLOW      0x04            /* overflow page */
+#define        P_RINTERNAL     0x08            /* recno internal page */
+#define        P_RLEAF         0x10            /* leaf page */
+#define P_TYPE         0x1f            /* type mask */
+#define        P_PRESERVE      0x20            /* never delete this chain of pages */
+       u_int32_t flags;
+
+       indx_t  lower;                  /* lower bound of free space on page */
+       indx_t  upper;                  /* upper bound of free space on page */
+       indx_t  linp;                /* indx_t-aligned VAR. LENGTH DATA */
+} PAGE;
+
+/* First and next index. */
+#define        BTDATAOFF                                                       \
+       (sizeof(pgno_t) + sizeof(pgno_t) + sizeof(pgno_t) +             \
+           sizeof(u_int32_t) + sizeof(indx_t) + sizeof(indx_t))
+#define        NEXTINDEX(p)    (((p)->lower - BTDATAOFF) / sizeof(indx_t))
+
+/*
+ * For pages other than overflow pages, there is an array of offsets into the
+ * rest of the page immediately following the page header.  Each offset is to
+ * an item which is unique to the type of page.  The h_lower offset is just
+ * past the last filled-in index.  The h_upper offset is the first item on the
+ * page.  Offsets are from the beginning of the page.
+ *
+ * If an item is too big to store on a single page, a flag is set and the item
+ * is a { page, size } pair such that the page is the first page of an overflow
+ * chain with size bytes of item.  Overflow pages are simply bytes without any
+ * external structure.
+ *
+ * The page number and size fields in the items are pgno_t-aligned so they can
+ * be manipulated without copying.  (This presumes that 32 bit items can be
+ * manipulated on this system.)
+ */
+#define        LALIGN(n)       (((n) + sizeof(pgno_t) - 1) & ~(sizeof(pgno_t) - 1))
+#define        NOVFLSIZE       (sizeof(pgno_t) + sizeof(u_int32_t))
+
+/*
+ * For the btree internal pages, the item is a key.  BINTERNALs are {key, pgno}
+ * pairs, such that the key compares less than or equal to all of the records
+ * on that page.  For a tree without duplicate keys, an internal page with two
+ * consecutive keys, a and b, will have all records greater than or equal to a
+ * and less than b stored on the page associated with a.  Duplicate keys are
+ * somewhat special and can cause duplicate internal and leaf page records and
+ * some minor modifications of the above rule.
+ */
+typedef struct _binternal {
+       u_int32_t ksize;                /* key size */
+       pgno_t  pgno;                   /* page number stored on */
+#define        P_BIGDATA       0x01            /* overflow data */
+#define        P_BIGKEY        0x02            /* overflow key */
+       u_char  flags;
+       char    bytes;               /* data */
+} BINTERNAL;
+
+/* Get the page's BINTERNAL structure at index indx. */
+#define        GETBINTERNAL(pg, indx)                                          \
+       ((BINTERNAL *)((char *)(pg) + (pg)->linp[indx]))
+
+/* Get the number of bytes in the entry. */
+#define NBINTERNAL(len)                                                        \
+       LALIGN(sizeof(u_int32_t) + sizeof(pgno_t) + sizeof(u_char) + (len))
+
+/* Copy a BINTERNAL entry to the page. */
+#define        WR_BINTERNAL(p, size, pgno, flags) {                            \
+       *(u_int32_t *)p = size;                                         \
+       p += sizeof(u_int32_t);                                         \
+       *(pgno_t *)p = pgno;                                            \
+       p += sizeof(pgno_t);                                            \
+       *(u_char *)p = flags;                                           \
+       p += sizeof(u_char);                                            \
+}
+
+/*
+ * For the recno internal pages, the item is a page number with the number of
+ * keys found on that page and below.
+ */
+typedef struct _rinternal {
+       recno_t nrecs;                  /* number of records */
+       pgno_t  pgno;                   /* page number stored below */
+} RINTERNAL;
+
+/* Get the page's RINTERNAL structure at index indx. */
+#define        GETRINTERNAL(pg, indx)                                          \
+       ((RINTERNAL *)((char *)(pg) + (pg)->linp[indx]))
+
+/* Get the number of bytes in the entry. */
+#define NRINTERNAL                                                     \
+       LALIGN(sizeof(recno_t) + sizeof(pgno_t))
+
+/* Copy a RINTERNAL entry to the page. */
+#define        WR_RINTERNAL(p, nrecs, pgno) {                                  \
+       *(recno_t *)p = nrecs;                                          \
+       p += sizeof(recno_t);                                           \
+       *(pgno_t *)p = pgno;                                            \
+}
+
+/* For the btree leaf pages, the item is a key and data pair. */
+typedef struct _bleaf {
+       u_int32_t       ksize;          /* size of key */
+       u_int32_t       dsize;          /* size of data */
+       u_char  flags;                  /* P_BIGDATA, P_BIGKEY */
+       char    bytes;               /* data */
+} BLEAF;
+
+/* Get the page's BLEAF structure at index indx. */
+#define        GETBLEAF(pg, indx)                                              \
+       ((BLEAF *)((char *)(pg) + (pg)->linp[indx]))
+
+/* Get the number of bytes in the entry. */
+#define NBLEAF(p)      NBLEAFDBT((p)->ksize, (p)->dsize)
+
+/* Get the number of bytes in the user's key/data pair. */
+#define NBLEAFDBT(ksize, dsize)                                                \
+       LALIGN(sizeof(u_int32_t) + sizeof(u_int32_t) + sizeof(u_char) + \
+           (ksize) + (dsize))
+
+/* Copy a BLEAF entry to the page. */
+#define        WR_BLEAF(p, key, data, flags) {                                 \
+       *(u_int32_t *)p = key->size;                                    \
+       p += sizeof(u_int32_t);                                         \
+       *(u_int32_t *)p = data->size;                                   \
+       p += sizeof(u_int32_t);                                         \
+       *(u_char *)p = flags;                                           \
+       p += sizeof(u_char);                                            \
+       memmove(p, key->data, key->size);                               \
+       p += key->size;                                                 \
+       memmove(p, data->data, data->size);                             \
+}
+
+/* For the recno leaf pages, the item is a data entry. */
+typedef struct _rleaf {
+       u_int32_t       dsize;          /* size of data */
+       u_char  flags;                  /* P_BIGDATA */
+       char    bytes;
+} RLEAF;
+
+/* Get the page's RLEAF structure at index indx. */
+#define        GETRLEAF(pg, indx)                                              \
+       ((RLEAF *)((char *)(pg) + (pg)->linp[indx]))
+
+/* Get the number of bytes in the entry. */
+#define NRLEAF(p)      NRLEAFDBT((p)->dsize)
+
+/* Get the number of bytes from the user's data. */
+#define        NRLEAFDBT(dsize)                                                \
+       LALIGN(sizeof(u_int32_t) + sizeof(u_char) + (dsize))
+
+/* Copy a RLEAF entry to the page. */
+#define        WR_RLEAF(p, data, flags) {                                      \
+       *(u_int32_t *)p = data->size;                                   \
+       p += sizeof(u_int32_t);                                         \
+       *(u_char *)p = flags;                                           \
+       p += sizeof(u_char);                                            \
+       memmove(p, data->data, data->size);                             \
+}
+
+/*
+ * A record in the tree is either a pointer to a page and an index in the page
+ * or a page number and an index.  These structures are used as a cursor, stack
+ * entry and search returns as well as to pass records to other routines.
+ *
+ * One comment about searches.  Internal page searches must find the largest
+ * record less than key in the tree so that descents work.  Leaf page searches
+ * must find the smallest record greater than key so that the returned index
+ * is the record's correct position for insertion.
+ */
+typedef struct _epgno {
+       pgno_t  pgno;                   /* the page number */
+       indx_t  index;                  /* the index on the page */
+} EPGNO;
+
+typedef struct _epg {
+       PAGE    *page;                  /* the (pinned) page */
+       indx_t   index;                 /* the index on the page */
+} EPG;
+
+/*
+ * About cursors.  The cursor (and the page that contained the key/data pair
+ * that it referenced) can be deleted, which makes things a bit tricky.  If
+ * there are no duplicates of the cursor key in the tree (i.e. B_NODUPS is set
+ * or there simply aren't any duplicates of the key) we copy the key that it
+ * referenced when it's deleted, and reacquire a new cursor key if the cursor
+ * is used again.  If there are duplicates keys, we move to the next/previous
+ * key, and set a flag so that we know what happened.  NOTE: if duplicate (to
+ * the cursor) keys are added to the tree during this process, it is undefined
+ * if they will be returned or not in a cursor scan.
+ *
+ * The flags determine the possible states of the cursor:
+ *
+ * CURS_INIT   The cursor references *something*.
+ * CURS_ACQUIRE        The cursor was deleted, and a key has been saved so that
+ *             we can reacquire the right position in the tree.
+ * CURS_AFTER, CURS_BEFORE
+ *             The cursor was deleted, and now references a key/data pair
+ *             that has not yet been returned, either before or after the
+ *             deleted key/data pair.
+ * XXX
+ * This structure is broken out so that we can eventually offer multiple
+ * cursors as part of the DB interface.
+ */
+typedef struct _cursor {
+       EPGNO    pg;                    /* B: Saved tree reference. */
+       DBT      key;                   /* B: Saved key, or key.data == NULL. */
+       recno_t  rcursor;               /* R: recno cursor (1-based) */
+
+#define        CURS_ACQUIRE    0x01            /*  B: Cursor needs to be reacquired. */
+#define        CURS_AFTER      0x02            /*  B: Unreturned cursor after key. */
+#define        CURS_BEFORE     0x04            /*  B: Unreturned cursor before key. */
+#define        CURS_INIT       0x08            /* RB: Cursor initialized. */
+       u_int8_t flags;
+} CURSOR;
+
+/*
+ * The metadata of the tree.  The nrecs field is used only by the RECNO code.
+ * This is because the btree doesn't really need it and it requires that every
+ * put or delete call modify the metadata.
+ */
+typedef struct _btmeta {
+       u_int32_t       magic;          /* magic number */
+       u_int32_t       version;        /* version */
+       u_int32_t       psize;          /* page size */
+       u_int32_t       free;           /* page number of first free page */
+       u_int32_t       nrecs;          /* R: number of records */
+
+#define        SAVEMETA        (B_NODUPS | R_RECNO)
+       u_int32_t       flags;          /* bt_flags & SAVEMETA */
+} BTMETA;
+
+/* The in-memory btree/recno data structure. */
+typedef struct _btree {
+       MPOOL    *bt_mp;                /* memory pool cookie */
+
+       DB       *bt_dbp;               /* pointer to enclosing DB */
+
+       EPG       bt_cur;               /* current (pinned) page */
+       PAGE     *bt_pinned;            /* page pinned across calls */
+
+       CURSOR    bt_cursor;            /* cursor */
+
+#define        BT_PUSH(t, p, i) {                                              \
+       t->bt_sp->pgno = p;                                             \
+       t->bt_sp->index = i;                                            \
+       ++t->bt_sp;                                                     \
+}
+#define        BT_POP(t)       (t->bt_sp == t->bt_stack ? NULL : --t->bt_sp)
+#define        BT_CLR(t)       (t->bt_sp = t->bt_stack)
+       EPGNO     bt_stack;         /* stack of parent pages */
+       EPGNO    *bt_sp;                /* current stack pointer */
+
+       DBT       bt_rkey;              /* returned key */
+       DBT       bt_rdata;             /* returned data */
+
+       int       bt_fd;                /* tree file descriptor */
+
+       pgno_t    bt_free;              /* next free page */
+       u_int32_t bt_psize;             /* page size */
+       indx_t    bt_ovflsize;          /* cut-off for key/data overflow */
+       int       bt_lorder;            /* byte order */
+                                       /* sorted order */
+       enum { NOT, BACK, FORWARD } bt_order;
+       EPGNO     bt_last;              /* last insert */
+
+                                       /* B: key comparison function */
+       int     (*bt_cmp) __P((const DBT *, const DBT *));
+                                       /* B: prefix comparison function */
+       size_t  (*bt_pfx) __P((const DBT *, const DBT *));
+                                       /* R: recno input function */
+       int     (*bt_irec) __P((struct _btree *, recno_t));
+
+       FILE     *bt_rfp;               /* R: record FILE pointer */
+       int       bt_rfd;               /* R: record file descriptor */
+
+       caddr_t   bt_cmap;              /* R: current point in mapped space */
+       caddr_t   bt_smap;              /* R: start of mapped space */
+       caddr_t   bt_emap;              /* R: end of mapped space */
+       size_t    bt_msize;             /* R: size of mapped region. */
+
+       recno_t   bt_nrecs;             /* R: number of records */
+       size_t    bt_reclen;            /* R: fixed record length */
+       u_char    bt_bval;              /* R: delimiting byte/pad character */
+
+/*
+ * NB:
+ * B_NODUPS and R_RECNO are stored on disk, and may not be changed.
+ */
+#define        B_INMEM         0x00001         /* in-memory tree */
+#define        B_MODIFIED      0x00004         /* tree modified */
+#define        B_NEEDSWAP      0x00008         /* if byte order requires swapping */
+#define        B_RDONLY        0x00010         /* read-only tree */
+
+#define        B_NODUPS        0x00020         /* no duplicate keys permitted */
+#define        R_RECNO         0x00080         /* record oriented tree */
+
+#define        R_CLOSEFP       0x00040         /* opened a file pointer */
+#define        R_EOF           0x00100         /* end of input file reached. */
+#define        R_FIXLEN        0x00200         /* fixed length records */
+#define        R_MEMMAPPED     0x00400         /* memory mapped file. */
+#define        R_INMEM         0x00800         /* in-memory file */
+#define        R_MODIFIED      0x01000         /* modified file */
+#define        R_RDONLY        0x02000         /* read-only file */
+
+#define        B_DB_LOCK       0x04000         /* DB_LOCK specified. */
+#define        B_DB_SHMEM      0x08000         /* DB_SHMEM specified. */
+#define        B_DB_TXN        0x10000         /* DB_TXN specified. */
+       u_int32_t flags;
+} BTREE;
+
+#include "extern.h"
diff --git a/db1-ast/btree/extern.h b/db1-ast/btree/extern.h
new file mode 100755 (executable)
index 0000000..ebd9c54
--- /dev/null
@@ -0,0 +1,70 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ *     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.
+ *
+ *     @(#)extern.h    8.10 (Berkeley) 7/20/94
+ */
+
+int     __bt_close __P((DB *));
+int     __bt_cmp __P((BTREE *, const DBT *, EPG *));
+int     __bt_crsrdel __P((BTREE *, EPGNO *));
+int     __bt_defcmp __P((const DBT *, const DBT *));
+size_t  __bt_defpfx __P((const DBT *, const DBT *));
+int     __bt_delete __P((const DB *, const DBT *, u_int));
+int     __bt_dleaf __P((BTREE *, const DBT *, PAGE *, u_int));
+int     __bt_fd __P((const DB *));
+int     __bt_free __P((BTREE *, PAGE *));
+int     __bt_get __P((const DB *, const DBT *, DBT *, u_int));
+PAGE   *__bt_new __P((BTREE *, pgno_t *));
+void    __bt_pgin __P((void *, pgno_t, void *));
+void    __bt_pgout __P((void *, pgno_t, void *));
+int     __bt_push __P((BTREE *, pgno_t, int));
+int     __bt_put __P((const DB *dbp, DBT *, const DBT *, u_int));
+int     __bt_ret __P((BTREE *, EPG *, DBT *, DBT *, DBT *, DBT *, int));
+EPG    *__bt_search __P((BTREE *, const DBT *, int *));
+int     __bt_seq __P((const DB *, DBT *, DBT *, u_int));
+void    __bt_setcur __P((BTREE *, pgno_t, u_int));
+int     __bt_split __P((BTREE *, PAGE *,
+           const DBT *, const DBT *, int, size_t, u_int32_t));
+int     __bt_sync __P((const DB *, u_int));
+
+int     __ovfl_delete __P((BTREE *, void *));
+int     __ovfl_get __P((BTREE *, void *, size_t *, void **, size_t *));
+int     __ovfl_put __P((BTREE *, const DBT *, pgno_t *));
+
+#ifdef DEBUG
+void    __bt_dnpage __P((DB *, pgno_t));
+void    __bt_dpage __P((PAGE *));
+void    __bt_dump __P((DB *));
+#endif
+#ifdef STATISTICS
+void    __bt_stat __P((DB *));
+#endif
diff --git a/db1-ast/db/db.c b/db1-ast/db/db.c
new file mode 100755 (executable)
index 0000000..0bee00b
--- /dev/null
@@ -0,0 +1,109 @@
+/*-
+ * Copyright (c) 1991, 1993
+ *     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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)db.c       8.4 (Berkeley) 2/21/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdio.h>
+
+#include <db.h>
+
+#define dbopen __dbopen
+
+DB *
+dbopen(fname, flags, mode, type, openinfo)
+       const char *fname;
+       int flags, mode;
+       DBTYPE type;
+       const void *openinfo;
+{
+
+#define        DB_FLAGS        (DB_LOCK | DB_SHMEM | DB_TXN)
+#define        USE_OPEN_FLAGS                                                  \
+       (O_CREAT | O_EXCL | O_EXLOCK | O_NONBLOCK | O_RDONLY |          \
+        O_RDWR | O_SHLOCK | O_TRUNC)
+
+       if ((flags & ~(USE_OPEN_FLAGS | DB_FLAGS)) == 0)
+               switch (type) {
+               case DB_BTREE:
+                       return (__bt_open(fname, flags & USE_OPEN_FLAGS,
+                           mode, openinfo, flags & DB_FLAGS));
+               case DB_HASH:
+                       return (__hash_open(fname, flags & USE_OPEN_FLAGS,
+                           mode, openinfo, flags & DB_FLAGS));
+               case DB_RECNO:
+                       return (__rec_open(fname, flags & USE_OPEN_FLAGS,
+                           mode, openinfo, flags & DB_FLAGS));
+               }
+       errno = EINVAL;
+       return (NULL);
+}
+#undef dbopen
+#define weak_alias(original, alias) \
+        asm (".weak " #alias "\n" #alias " = " #original);
+weak_alias (__dbopen, dbopen)
+
+static int
+__dberr __P((void))
+{
+       return (RET_ERROR);
+}
+
+/*
+ * __DBPANIC -- Stop.
+ *
+ * Parameters:
+ *     dbp:    pointer to the DB structure.
+ */
+void
+__dbpanic(dbp)
+       DB *dbp;
+{
+       /* The only thing that can succeed is a close. */
+       dbp->del = (int (*)__P((const struct __db *,
+                               const DBT *, u_int))) __dberr;
+       dbp->get = (int (*)__P((const struct __db *,
+                               const DBT *, DBT *, u_int))) __dberr;
+       dbp->put = (int (*)__P((const struct __db *,
+                               DBT *, const DBT *, u_int))) __dberr;
+       dbp->seq = (int (*)__P((const struct __db *,
+                               DBT *, DBT *, u_int))) __dberr;
+       dbp->sync = (int (*)__P((const struct __db *, u_int))) __dberr;
+       dbp->fd = (int (*)__P((const struct __db *))) __dberr;
+}
new file mode 100755 (executable)
index 0000000..f29ccf7
--- /dev/null
@@ -0,0 +1,72 @@
+
+This package implements a superset of the hsearch and dbm/ndbm libraries.
+
+Test Programs:
+       All test programs which need key/data pairs expect them entered
+       with key and data on separate lines
+
+       tcreat3.c
+               Takes
+                       bucketsize (bsize),
+                       fill factor (ffactor), and
+                       initial number of elements (nelem).
+               Creates a hash table named hashtest containing the
+               keys/data pairs entered from standard in.
+       thash4.c
+               Takes
+                       bucketsize (bsize),
+                       fill factor (ffactor),
+                       initial number of elements (nelem)
+                       bytes of cache (ncached), and
+                       file from which to read data  (fname)
+               Creates a table from the key/data pairs on standard in and
+               then does a read of each key/data in fname
+       tdel.c
+               Takes
+                       bucketsize (bsize), and
+                       fill factor (ffactor).
+                       file from which to read data (fname)
+               Reads each key/data pair from fname and deletes the
+               key from the hash table hashtest
+       tseq.c
+               Reads the key/data pairs in the file hashtest and writes them
+               to standard out.
+               Takes
+                       butes of cache (ncached).
+               Reads key/data pairs from standard in and looks them up
+               in the file hashtest.
+       tverify.c
+               Reads key/data pairs from standard in, looks them up
+               in the file hashtest, and verifies that the data is
+               correct.
+
+NOTES:
+
+The file search.h is provided for using the hsearch compatible interface
+on BSD systems.  On System V derived systems, search.h should appear in
+/usr/include.
+
+The man page ../man/db.3 explains the interface to the hashing system.
+The file hash.ps is a postscript copy of a paper explaining
+the history, implementation, and performance of the hash package.
+
+"bugs" or idiosyncracies
+
+If you have a lot of overflows, it is possible to run out of overflow
+pages.  Currently, this will cause a message to be printed on stderr.
+Eventually, this will be indicated by a return error code.
+
+If you are using the ndbm interface and exit without flushing or closing the
+file, you may lose updates since the package buffers all writes.  Also,
+the db interface only creates a single database file.  To avoid overwriting
+the user's original file, the suffix ".db" is appended to the file name
+.dir and .pag files, it will break.
+
+There is a fundamental difference between this package and the old hsearch.
+Hsearch requires the user to maintain the keys and data in the application's
+allocated memory while hash takes care of all storage management.  The down
+side is that the byte strings passed in the ENTRY structure must be null
+terminated (both the keys and the data).
diff --git a/db1-ast/hash/extern.h b/db1-ast/hash/extern.h
new file mode 100755 (executable)
index 0000000..4f1f23d
--- /dev/null
@@ -0,0 +1,65 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ *     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.
+ *
+ *     @(#)extern.h    8.4 (Berkeley) 6/16/94
+ */
+
+int     __addel __P((HTAB *, BUFHEAD *, const DBT *, const DBT *));
+int     __big_delete __P((HTAB *, BUFHEAD *));
+int     __big_insert __P((HTAB *, BUFHEAD *, const DBT *, const DBT *));
+int     __big_keydata __P((HTAB *, BUFHEAD *, DBT *, DBT *, int));
+int     __big_return __P((HTAB *, BUFHEAD *, int, DBT *, int));
+               int, u_int32_t, SPLIT_RETURN *));
+int     __buf_free __P((HTAB *, int, int));
+void    __buf_init __P((HTAB *, int));
+u_int32_t       __call_hash __P((HTAB *, char *, int));
+int     __delpair __P((HTAB *, BUFHEAD *, int));
+int     __expand_table __P((HTAB *));
+int     __find_bigpair __P((HTAB *, BUFHEAD *, int, char *, int));
+u_int16_t       __find_last_page __P((HTAB *, BUFHEAD **));
+void    __free_ovflpage __P((HTAB *, BUFHEAD *));
+int     __get_page __P((HTAB *, char *, u_int32_t, int, int, int));
+int     __ibitmap __P((HTAB *, int, int, int));
+u_int32_t       __hash_log2 __P((u_int32_t));
+int     __put_page __P((HTAB *, char *, u_int32_t, int, int));
+void    __reclaim_buf __P((HTAB *, BUFHEAD *));
+int     __split_page __P((HTAB *, u_int32_t, u_int32_t));
+
+/* Default hash routine. */
+extern u_int32_t (*__default_hash) __P((const void *, size_t));
+
+#ifdef HASH_STATISTICS
+extern int hash_accesses, hash_collisions, hash_expansions, hash_overflows;
+#endif
diff --git a/db1-ast/hash/hash.c b/db1-ast/hash/hash.c
new file mode 100755 (executable)
index 0000000..99592ea
--- /dev/null
@@ -0,0 +1,999 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *     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[] = "@(#)hash.c     8.9 (Berkeley) 6/16/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#ifdef DEBUG
+#include <assert.h>
+#endif
+
+#include <db.h>
+#include "hash.h"
+#include "page.h"
+#include "extern.h"
+
+static int   alloc_segs __P((HTAB *, int));
+static int   flush_meta __P((HTAB *));
+static int   hash_access __P((HTAB *, ACTION, DBT *, DBT *));
+static int   hash_close __P((DB *));
+static int   hash_delete __P((const DB *, const DBT *, u_int32_t));
+static int   hash_fd __P((const DB *));
+static int   hash_get __P((const DB *, const DBT *, DBT *, u_int32_t));
+static int   hash_put __P((const DB *, DBT *, const DBT *, u_int32_t));
+static void *hash_realloc __P((SEGMENT **, int, int));
+static int   hash_seq __P((const DB *, DBT *, DBT *, u_int32_t));
+static int   hash_sync __P((const DB *, u_int32_t));
+static int   hdestroy __P((HTAB *));
+static HTAB *init_hash __P((HTAB *, const char *, HASHINFO *));
+static int   init_htab __P((HTAB *, int));
+#if BYTE_ORDER == LITTLE_ENDIAN
+static void  swap_header_copy __P((HASHHDR *, HASHHDR *));
+#endif
+
+/* Fast arithmetic, relying on powers of 2, */
+#define MOD(x, y)              ((x) & ((y) - 1))
+
+#define RETURN_ERROR(ERR, LOC) { save_errno = ERR; goto LOC; }
+
+/* Return values */
+#define        SUCCESS  (0)
+#define        ERROR   (-1)
+#define        ABNORMAL (1)
+
+#ifdef HASH_STATISTICS
+int hash_accesses, hash_collisions, hash_expansions, hash_overflows;
+#endif
+
+/************************** INTERFACE ROUTINES ***************************/
+/* OPEN/CLOSE */
+
+extern DB *
+__hash_open(file, flags, mode, info, dflags)
+       const char *file;
+       int flags, mode, dflags;
+       const HASHINFO *info;   /* Special directives for create */
+{
+       HTAB *hashp;
+       struct stat statbuf;
+       DB *dbp;
+       int bpages, hdrsize, new_table, nsegs, save_errno;
+
+       if ((flags & O_ACCMODE) == O_WRONLY) {
+               errno = EINVAL;
+               return (NULL);
+       }
+
+       if (!(hashp = (HTAB *)calloc(1, sizeof(HTAB))))
+               return (NULL);
+       hashp->fp = -1;
+
+       /*
+        * Even if user wants write only, we need to be able to read
+        * the actual file, so we need to open it read/write. But, the
+        * field in the hashp structure needs to be accurate so that
+        * we can check accesses.
+        */
+       hashp->flags = flags;
+
+       new_table = 0;
+       if (!file || (flags & O_TRUNC) ||
+           (stat(file, &statbuf) && (errno == ENOENT))) {
+               if (errno == ENOENT)
+                       errno = 0; /* Just in case someone looks at errno */
+               new_table = 1;
+       }
+       if (file) {
+               if ((hashp->fp = open(file, flags, mode)) == -1)
+                       RETURN_ERROR(errno, error0);
+               (void)fcntl(hashp->fp, F_SETFD, 1);
+       }
+       if (new_table) {
+               if (!(hashp = init_hash(hashp, file, (HASHINFO *)info)))
+                       RETURN_ERROR(errno, error1);
+       } else {
+               /* Table already exists */
+               if (info && info->hash)
+                       hashp->hash = info->hash;
+               else
+                       hashp->hash = __default_hash;
+
+               hdrsize = read(hashp->fp, &hashp->hdr, sizeof(HASHHDR));
+#if BYTE_ORDER == LITTLE_ENDIAN
+#endif
+               if (hdrsize == -1)
+                       RETURN_ERROR(errno, error1);
+               if (hdrsize != sizeof(HASHHDR))
+                       RETURN_ERROR(EFTYPE, error1);
+               /* Verify file type, versions and hash function */
+               if (hashp->MAGIC != HASHMAGIC)
+                       RETURN_ERROR(EFTYPE, error1);
+#define        OLDHASHVERSION  1
+               if (hashp->VERSION != HASHVERSION &&
+                   hashp->VERSION != OLDHASHVERSION)
+                       RETURN_ERROR(EFTYPE, error1);
+               if (hashp->hash(CHARKEY, sizeof(CHARKEY))
+                   != (u_int32_t) hashp->H_CHARKEY)
+                       RETURN_ERROR(EFTYPE, error1);
+               /*
+                * Figure out how many segments we need.  Max_Bucket is the
+                * maximum bucket number, so the number of buckets is
+                * max_bucket + 1.
+                */
+               nsegs = (hashp->MAX_BUCKET + 1 + hashp->SGSIZE - 1) /
+                        hashp->SGSIZE;
+               hashp->nsegs = 0;
+               if (alloc_segs(hashp, nsegs))
+                       /*
+                        * If alloc_segs fails, table will have been destroyed
+                        * and errno will have been set.
+                        */
+                       return (NULL);
+               /* Read in bitmaps */
+               bpages = (hashp->SPARES[hashp->OVFL_POINT] +
+                   (hashp->BSIZE << BYTE_SHIFT) - 1) >>
+                   (hashp->BSHIFT + BYTE_SHIFT);
+
+               hashp->nmaps = bpages;
+               (void)memset(&hashp->mapp, 0, bpages * sizeof(u_int32_t *));
+       }
+
+       /* Initialize Buffer Manager */
+       if (info && info->cachesize)
+               __buf_init(hashp, info->cachesize);
+       else
+               __buf_init(hashp, DEF_BUFSIZE);
+
+       hashp->new_file = new_table;
+       hashp->save_file = file && (hashp->flags & O_ACCMODE) != O_RDONLY;
+       hashp->cbucket = -1;
+       if (!(dbp = (DB *)malloc(sizeof(DB)))) {
+               save_errno = errno;
+               hdestroy(hashp);
+               errno = save_errno;
+               return (NULL);
+       }
+       dbp->internal = hashp;
+       dbp->close = hash_close;
+       dbp->del = hash_delete;
+       dbp->fd = hash_fd;
+       dbp->get = hash_get;
+       dbp->put = hash_put;
+       dbp->seq = hash_seq;
+       dbp->sync = hash_sync;
+       dbp->type = DB_HASH;
+
+#ifdef DEBUG
+       (void)fprintf(stderr,
+"%s\n%s%x\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%x\n%s%x\n%s%d\n%s%d\n",
+           "init_htab:",
+           "TABLE POINTER   ", hashp,
+           "BUCKET SIZE     ", hashp->BSIZE,
+           "BUCKET SHIFT    ", hashp->BSHIFT,
+           "DIRECTORY SIZE  ", hashp->DSIZE,
+           "SEGMENT SIZE    ", hashp->SGSIZE,
+           "SEGMENT SHIFT   ", hashp->SSHIFT,
+           "FILL FACTOR     ", hashp->FFACTOR,
+           "MAX BUCKET      ", hashp->MAX_BUCKET,
+           "OVFL POINT      ", hashp->OVFL_POINT,
+           "LAST FREED      ", hashp->LAST_FREED,
+           "NSEGS           ", hashp->nsegs,
+           "NKEYS           ", hashp->NKEYS);
+#endif
+#ifdef HASH_STATISTICS
+       hash_overflows = hash_accesses = hash_collisions = hash_expansions = 0;
+#endif
+       return (dbp);
+
+error1:
+       if (hashp != NULL)
+               (void)close(hashp->fp);
+
+error0:
+       free(hashp);
+       errno = save_errno;
+       return (NULL);
+}
+
+static int
+hash_close(dbp)
+       DB *dbp;
+{
+       HTAB *hashp;
+       int retval;
+
+       if (!dbp)
+               return (ERROR);
+
+       hashp = (HTAB *)dbp->internal;
+       retval = hdestroy(hashp);
+       free(dbp);
+       return (retval);
+}
+
+static int
+hash_fd(dbp)
+       const DB *dbp;
+{
+       HTAB *hashp;
+
+       if (!dbp)
+               return (ERROR);
+
+       hashp = (HTAB *)dbp->internal;
+       if (hashp->fp == -1) {
+               errno = ENOENT;
+               return (-1);
+       }
+       return (hashp->fp);
+}
+
+/************************** LOCAL CREATION ROUTINES **********************/
+static HTAB *
+init_hash(hashp, file, info)
+       HTAB *hashp;
+       const char *file;
+       HASHINFO *info;
+{
+#ifdef _STATBUF_ST_BLKSIZE
+       struct stat statbuf;
+#endif
+       int nelem;
+
+       nelem = 1;
+       hashp->NKEYS = 0;
+       hashp->LORDER = BYTE_ORDER;
+       hashp->BSIZE = DEF_BUCKET_SIZE;
+       hashp->BSHIFT = DEF_BUCKET_SHIFT;
+       hashp->SGSIZE = DEF_SEGSIZE;
+       hashp->SSHIFT = DEF_SEGSIZE_SHIFT;
+       hashp->DSIZE = DEF_DIRSIZE;
+       hashp->FFACTOR = DEF_FFACTOR;
+       hashp->hash = __default_hash;
+       memset(hashp->SPARES, 0, sizeof(hashp->SPARES));
+       memset(hashp->BITMAPS, 0, sizeof (hashp->BITMAPS));
+
+       /* Fix bucket size to be optimal for file system */
+#ifdef _STATBUF_ST_BLKSIZE
+       if (file != NULL) {
+               if (stat(file, &statbuf))
+                       return (NULL);
+               hashp->BSIZE = statbuf.st_blksize;
+               hashp->BSHIFT = __hash_log2(hashp->BSIZE);
+       }
+#endif
+
+       if (info) {
+               if (info->bsize) {
+                       /* Round pagesize up to power of 2 */
+                       hashp->BSHIFT = __hash_log2(info->bsize);
+                       hashp->BSIZE = 1 << hashp->BSHIFT;
+                       if (hashp->BSIZE > MAX_BSIZE) {
+                               errno = EINVAL;
+                               return (NULL);
+                       }
+               }
+               if (info->ffactor)
+                       hashp->FFACTOR = info->ffactor;
+               if (info->hash)
+                       hashp->hash = info->hash;
+               if (info->nelem)
+                       nelem = info->nelem;
+               if (info->lorder) {
+                       if (info->lorder != BIG_ENDIAN &&
+                           info->lorder != LITTLE_ENDIAN) {
+                               errno = EINVAL;
+                               return (NULL);
+                       }
+                       hashp->LORDER = info->lorder;
+               }
+       }
+       /* init_htab should destroy the table and set errno if it fails */
+       if (init_htab(hashp, nelem))
+               return (NULL);
+       else
+               return (hashp);
+}
+/*
+ * This calls alloc_segs which may run out of memory.  Alloc_segs will destroy
+ * the table and set errno, so we just pass the error information along.
+ *
+ * Returns 0 on No Error
+ */
+static int
+init_htab(hashp, nelem)
+       HTAB *hashp;
+       int nelem;
+{
+       register int nbuckets, nsegs;
+       int l2;
+
+       /*
+        * Divide number of elements by the fill factor and determine a
+        * desired number of buckets.  Allocate space for the next greater
+        * power of two number of buckets.
+        */
+       nelem = (nelem - 1) / hashp->FFACTOR + 1;
+
+       l2 = __hash_log2(MAX(nelem, 2));
+       nbuckets = 1 << l2;
+
+       hashp->SPARES[l2] = l2 + 1;
+       hashp->SPARES[l2 + 1] = l2 + 1;
+       hashp->OVFL_POINT = l2;
+       hashp->LAST_FREED = 2;
+
+       /* First bitmap page is at: splitpoint l2 page offset 1 */
+       if (__ibitmap(hashp, OADDR_OF(l2, 1), l2 + 1, 0))
+               return (-1);
+
+       hashp->MAX_BUCKET = hashp->LOW_MASK = nbuckets - 1;
+       hashp->HIGH_MASK = (nbuckets << 1) - 1;
+       hashp->HDRPAGES = ((MAX(sizeof(HASHHDR), MINHDRSIZE) - 1) >>
+           hashp->BSHIFT) + 1;
+
+       nsegs = (nbuckets - 1) / hashp->SGSIZE + 1;
+       nsegs = 1 << __hash_log2(nsegs);
+
+       if (nsegs > hashp->DSIZE)
+               hashp->DSIZE = nsegs;
+       return (alloc_segs(hashp, nsegs));
+}
+
+/********************** DESTROY/CLOSE ROUTINES ************************/
+
+/*
+ * Flushes any changes to the file if necessary and destroys the hashp
+ * structure, freeing all allocated space.
+ */
+static int
+hdestroy(hashp)
+       HTAB *hashp;
+{
+       int i, save_errno;
+
+       save_errno = 0;
+
+#ifdef HASH_STATISTICS
+       (void)fprintf(stderr, "hdestroy: accesses %ld collisions %ld\n",
+           hash_accesses, hash_collisions);
+       (void)fprintf(stderr, "hdestroy: expansions %ld\n",
+           hash_expansions);
+       (void)fprintf(stderr, "hdestroy: overflows %ld\n",
+           hash_overflows);
+       (void)fprintf(stderr, "keys %ld maxp %d segmentcount %d\n",
+           hashp->NKEYS, hashp->MAX_BUCKET, hashp->nsegs);
+
+       for (i = 0; i < NCACHED; i++)
+               (void)fprintf(stderr,
+                   "spares[%d] = %d\n", i, hashp->SPARES[i]);
+#endif
+       /*
+        * Call on buffer manager to free buffers, and if required,
+        * write them to disk.
+        */
+       if (__buf_free(hashp, 1, hashp->save_file))
+               save_errno = errno;
+       if (hashp->dir) {
+               free(*hashp->dir);      /* Free initial segments */
+               /* Free extra segments */
+               while (hashp->exsegs--)
+                       free(hashp->dir[--hashp->nsegs]);
+               free(hashp->dir);
+       }
+       if (flush_meta(hashp) && !save_errno)
+               save_errno = errno;
+       /* Free Bigmaps */
+       for (i = 0; i < hashp->nmaps; i++)
+               if (hashp->mapp[i])
+                       free(hashp->mapp[i]);
+
+       if (hashp->fp != -1)
+               (void)close(hashp->fp);
+
+       free(hashp);
+
+       if (save_errno) {
+               errno = save_errno;
+               return (ERROR);
+       }
+       return (SUCCESS);
+}
+/*
+ * Write modified pages to disk
+ *
+ * Returns:
+ *      0 == OK
+ *     -1 ERROR
+ */
+static int
+hash_sync(dbp, flags)
+       const DB *dbp;
+       u_int32_t flags;
+{
+       HTAB *hashp;
+
+       if (flags != 0) {
+               errno = EINVAL;
+               return (ERROR);
+       }
+
+       if (!dbp)
+               return (ERROR);
+
+       hashp = (HTAB *)dbp->internal;
+       if (!hashp->save_file)
+               return (0);
+       if (__buf_free(hashp, 0, 1) || flush_meta(hashp))
+               return (ERROR);
+       hashp->new_file = 0;
+       return (0);
+}
+
+/*
+ * Returns:
+ *      0 == OK
+ *     -1 indicates that errno should be set
+ */
+static int
+flush_meta(hashp)
+       HTAB *hashp;
+{
+       HASHHDR *whdrp;
+#if BYTE_ORDER == LITTLE_ENDIAN
+       HASHHDR whdr;
+#endif
+       int fp, i, wsize;
+
+       if (!hashp->save_file)
+               return (0);
+       hashp->MAGIC = HASHMAGIC;
+       hashp->VERSION = HASHVERSION;
+       hashp->H_CHARKEY = hashp->hash(CHARKEY, sizeof(CHARKEY));
+
+       fp = hashp->fp;
+       whdrp = &hashp->hdr;
+#if BYTE_ORDER == LITTLE_ENDIAN
+       whdrp = &whdr;
+#endif
+       if ((lseek(fp, (off_t)0, SEEK_SET) == -1) ||
+           ((wsize = write(fp, whdrp, sizeof(HASHHDR))) == -1))
+               return (-1);
+       else
+               if (wsize != sizeof(HASHHDR)) {
+                       errno = EFTYPE;
+                       hashp->errnum = errno;
+                       return (-1);
+               }
+       for (i = 0; i < NCACHED; i++)
+               if (hashp->mapp[i])
+                       if (__put_page(hashp, (char *)hashp->mapp[i],
+                               hashp->BITMAPS[i], 0, 1))
+                               return (-1);
+       return (0);
+}
+
+/*******************************SEARCH ROUTINES *****************************/
+/*
+ * All the access routines return
+ *
+ * Returns:
+ *      0 on SUCCESS
+ *      1 to indicate an external ERROR (i.e. key not found, etc)
+ *     -1 to indicate an internal ERROR (i.e. out of memory, etc)
+ */
+static int
+hash_get(dbp, key, data, flag)
+       const DB *dbp;
+       const DBT *key;
+       DBT *data;
+       u_int32_t flag;
+{
+       HTAB *hashp;
+
+       hashp = (HTAB *)dbp->internal;
+       if (flag) {
+               hashp->errnum = errno = EINVAL;
+               return (ERROR);
+       }
+       return (hash_access(hashp, HASH_GET, (DBT *)key, data));
+}
+
+static int
+hash_put(dbp, key, data, flag)
+       const DB *dbp;
+       DBT *key;
+       const DBT *data;
+       u_int32_t flag;
+{
+       HTAB *hashp;
+
+       hashp = (HTAB *)dbp->internal;
+       if (flag && flag != R_NOOVERWRITE) {
+               hashp->errnum = errno = EINVAL;
+               return (ERROR);
+       }
+       if ((hashp->flags & O_ACCMODE) == O_RDONLY) {
+               hashp->errnum = errno = EPERM;
+               return (ERROR);
+       }
+       return (hash_access(hashp, flag == R_NOOVERWRITE ?
+           HASH_PUTNEW : HASH_PUT, (DBT *)key, (DBT *)data));
+}
+
+static int
+hash_delete(dbp, key, flag)
+       const DB *dbp;
+       const DBT *key;
+       u_int32_t flag;         /* Ignored */
+{
+       HTAB *hashp;
+
+       hashp = (HTAB *)dbp->internal;
+       if (flag && flag != R_CURSOR) {
+               hashp->errnum = errno = EINVAL;
+               return (ERROR);
+       }
+       if ((hashp->flags & O_ACCMODE) == O_RDONLY) {
+               hashp->errnum = errno = EPERM;
+               return (ERROR);
+       }
+       return (hash_access(hashp, HASH_DELETE, (DBT *)key, NULL));
+}
+
+/*
+ * Assume that hashp has been set in wrapper routine.
+ */
+static int
+hash_access(hashp, action, key, val)
+       HTAB *hashp;
+       ACTION action;
+       DBT *key, *val;
+{
+       register u_int16_t *bp;
+       register int n, ndx, off, size;
+       register char *kp;
+       u_int16_t pageno;
+
+#ifdef HASH_STATISTICS
+       hash_accesses++;
+#endif
+
+       off = hashp->BSIZE;
+       size = key->size;
+       kp = (char *)key->data;
+       rbufp = __get_buf(hashp, __call_hash(hashp, kp, size), NULL, 0);
+       if (!rbufp)
+               return (ERROR);
+       save_bufp = rbufp;
+
+       /* Pin the bucket chain */
+       rbufp->flags |= BUF_PIN;
+       for (bp = (u_int16_t *)rbufp->page, n = *bp++, ndx = 1; ndx < n;)
+               if (bp >= REAL_KEY) {
+                       /* Real key/data pair */
+                       if (size == off - *bp &&
+                           memcmp(kp, rbufp->page + *bp, size) == 0)
+                               goto found;
+                       off = bp;
+#ifdef HASH_STATISTICS
+                       hash_collisions++;
+#endif
+                       bp += 2;
+                       ndx += 2;
+               } else if (bp == OVFLPAGE) {
+                       rbufp = __get_buf(hashp, *bp, rbufp, 0);
+                       if (!rbufp) {
+                               save_bufp->flags &= ~BUF_PIN;
+                               return (ERROR);
+                       }
+                       /* FOR LOOP INIT */
+                       bp = (u_int16_t *)rbufp->page;
+                       n = *bp++;
+                       ndx = 1;
+                       off = hashp->BSIZE;
+               } else if (bp < REAL_KEY) {
+                       if ((ndx =
+                           __find_bigpair(hashp, rbufp, ndx, kp, size)) > 0)
+                               goto found;
+                       if (ndx == -2) {
+                               bufp = rbufp;
+                               if (!(pageno =
+                                   __find_last_page(hashp, &bufp))) {
+                                       ndx = 0;
+                                       rbufp = bufp;
+                                       break;  /* FOR */
+                               }
+                               rbufp = __get_buf(hashp, pageno, bufp, 0);
+                               if (!rbufp) {
+                                       save_bufp->flags &= ~BUF_PIN;
+                                       return (ERROR);
+                               }
+                               /* FOR LOOP INIT */
+                               bp = (u_int16_t *)rbufp->page;
+                               n = *bp++;
+                               ndx = 1;
+                               off = hashp->BSIZE;
+                       } else {
+                               save_bufp->flags &= ~BUF_PIN;
+                               return (ERROR);
+                       }
+               }
+
+       /* Not found */
+       switch (action) {
+       case HASH_PUT:
+       case HASH_PUTNEW:
+               if (__addel(hashp, rbufp, key, val)) {
+                       save_bufp->flags &= ~BUF_PIN;
+                       return (ERROR);
+               } else {
+                       save_bufp->flags &= ~BUF_PIN;
+                       return (SUCCESS);
+               }
+       case HASH_GET:
+       case HASH_DELETE:
+       default:
+               save_bufp->flags &= ~BUF_PIN;
+               return (ABNORMAL);
+       }
+
+found:
+       switch (action) {
+       case HASH_PUTNEW:
+               save_bufp->flags &= ~BUF_PIN;
+               return (ABNORMAL);
+       case HASH_GET:
+               bp = (u_int16_t *)rbufp->page;
+               if (bp[ndx + 1] < REAL_KEY) {
+                       if (__big_return(hashp, rbufp, ndx, val, 0))
+                               return (ERROR);
+               } else {
+                       val->data = (u_char *)rbufp->page + (int)bp[ndx + 1];
+                       val->size = bp[ndx] - bp[ndx + 1];
+               }
+               break;
+       case HASH_PUT:
+               if ((__delpair(hashp, rbufp, ndx)) ||
+                   (__addel(hashp, rbufp, key, val))) {
+                       save_bufp->flags &= ~BUF_PIN;
+                       return (ERROR);
+               }
+               break;
+       case HASH_DELETE:
+               if (__delpair(hashp, rbufp, ndx))
+                       return (ERROR);
+               break;
+       default:
+               abort();
+       }
+       save_bufp->flags &= ~BUF_PIN;
+       return (SUCCESS);
+}
+
+static int
+hash_seq(dbp, key, data, flag)
+       const DB *dbp;
+       DBT *key, *data;
+       u_int32_t flag;
+{
+       register u_int32_t bucket;
+       HTAB *hashp;
+       u_int16_t *bp, ndx;
+
+       hashp = (HTAB *)dbp->internal;
+       if (flag && flag != R_FIRST && flag != R_NEXT) {
+               hashp->errnum = errno = EINVAL;
+               return (ERROR);
+       }
+#ifdef HASH_STATISTICS
+       hash_accesses++;
+#endif
+       if ((hashp->cbucket < 0) || (flag == R_FIRST)) {
+               hashp->cbucket = 0;
+               hashp->cndx = 1;
+               hashp->cpage = NULL;
+       }
+
+       for (bp = NULL; !bp || !bp; ) {
+               if (!(bufp = hashp->cpage)) {
+                       for (bucket = hashp->cbucket;
+                           bucket <= (u_int32_t) hashp->MAX_BUCKET;
+                           bucket++, hashp->cndx = 1) {
+                               bufp = __get_buf(hashp, bucket, NULL, 0);
+                               if (!bufp)
+                                       return (ERROR);
+                               hashp->cpage = bufp;
+                               bp = (u_int16_t *)bufp->page;
+                               if (bp)
+                                       break;
+                       }
+                       hashp->cbucket = bucket;
+                       if (hashp->cbucket > hashp->MAX_BUCKET) {
+                               hashp->cbucket = -1;
+                               return (ABNORMAL);
+                       }
+               } else
+                       bp = (u_int16_t *)hashp->cpage->page;
+
+#ifdef DEBUG
+               assert(bp);
+               assert(bufp);
+#endif
+               while (bp[hashp->cndx + 1] == OVFLPAGE) {
+                       bufp = hashp->cpage =
+                           __get_buf(hashp, bp[hashp->cndx], bufp, 0);
+                       if (!bufp)
+                               return (ERROR);
+                       bp = (u_int16_t *)(bufp->page);
+                       hashp->cndx = 1;
+               }
+               if (!bp) {
+                       hashp->cpage = NULL;
+                       ++hashp->cbucket;
+               }
+       }
+       ndx = hashp->cndx;
+       if (bp[ndx + 1] < REAL_KEY) {
+               if (__big_keydata(hashp, bufp, key, data, 1))
+                       return (ERROR);
+       } else {
+               key->data = (u_char *)hashp->cpage->page + bp[ndx];
+               key->size = (ndx > 1 ? bp[ndx - 1] : hashp->BSIZE) - bp[ndx];
+               data->data = (u_char *)hashp->cpage->page + bp[ndx + 1];
+               data->size = bp[ndx] - bp[ndx + 1];
+               ndx += 2;
+               if (ndx > bp) {
+                       hashp->cpage = NULL;
+                       hashp->cbucket++;
+                       hashp->cndx = 1;
+               } else
+                       hashp->cndx = ndx;
+       }
+       return (SUCCESS);
+}
+
+/********************************* UTILITIES ************************/
+
+/*
+ * Returns:
+ *      0 ==> OK
+ *     -1 ==> Error
+ */
+extern int
+__expand_table(hashp)
+       HTAB *hashp;
+{
+       u_int32_t old_bucket, new_bucket;
+       int dirsize, new_segnum, spare_ndx;
+
+#ifdef HASH_STATISTICS
+       hash_expansions++;
+#endif
+       new_bucket = ++hashp->MAX_BUCKET;
+       old_bucket = (hashp->MAX_BUCKET & hashp->LOW_MASK);
+
+       new_segnum = new_bucket >> hashp->SSHIFT;
+
+       /* Check if we need a new segment */
+       if (new_segnum >= hashp->nsegs) {
+               /* Check if we need to expand directory */
+               if (new_segnum >= hashp->DSIZE) {
+                       /* Reallocate directory */
+                       dirsize = hashp->DSIZE * sizeof(SEGMENT *);
+                       if (!hash_realloc(&hashp->dir, dirsize, dirsize << 1))
+                               return (-1);
+                       hashp->DSIZE = dirsize << 1;
+               }
+               if ((hashp->dir[new_segnum] =
+                   (SEGMENT)calloc(hashp->SGSIZE, sizeof(SEGMENT))) == NULL)
+                       return (-1);
+               hashp->exsegs++;
+               hashp->nsegs++;
+       }
+       /*
+        * If the split point is increasing (MAX_BUCKET's log base 2
+        * * increases), we need to copy the current contents of the spare
+        * split bucket to the next bucket.
+        */
+       spare_ndx = __hash_log2(hashp->MAX_BUCKET + 1);
+       if (spare_ndx > hashp->OVFL_POINT) {
+               hashp->SPARES[spare_ndx] = hashp->SPARES[hashp->OVFL_POINT];
+               hashp->OVFL_POINT = spare_ndx;
+       }
+
+       if (new_bucket > (u_int32_t) hashp->HIGH_MASK) {
+               /* Starting a new doubling */
+       }
+       /* Relocate records to the new bucket */
+       return (__split_page(hashp, old_bucket, new_bucket));
+}
+
+/*
+ * If realloc guarantees that the pointer is not destroyed if the realloc
+ * fails, then this routine can go away.
+ */
+static void *
+hash_realloc(p_ptr, oldsize, newsize)
+       SEGMENT **p_ptr;
+       int oldsize, newsize;
+{
+       register void *p;
+
+       if ((p = malloc(newsize))) {
+               memmove(p, *p_ptr, oldsize);
+               memset((char *)p + oldsize, 0, newsize - oldsize);
+               free(*p_ptr);
+               *p_ptr = p;
+       }
+       return (p);
+}
+
+extern u_int32_t
+__call_hash(hashp, k, len)
+       HTAB *hashp;
+       char *k;
+       int len;
+{
+       int n, bucket;
+
+       n = hashp->hash(k, len);
+       bucket = n & hashp->HIGH_MASK;
+       if (bucket > hashp->MAX_BUCKET)
+               bucket = bucket & hashp->LOW_MASK;
+       return (bucket);
+}
+
+/*
+ * Allocate segment table.  On error, destroy the table and set errno.
+ *
+ * Returns 0 on success
+ */
+static int
+alloc_segs(hashp, nsegs)
+       HTAB *hashp;
+       int nsegs;
+{
+       register int i;
+       register SEGMENT store;
+
+       int save_errno;
+
+       if ((hashp->dir =
+           (SEGMENT *)calloc(hashp->DSIZE, sizeof(SEGMENT *))) == NULL) {
+               save_errno = errno;
+               (void)hdestroy(hashp);
+               errno = save_errno;
+               return (-1);
+       }
+       /* Allocate segments */
+       if ((store =
+           (SEGMENT)calloc(nsegs << hashp->SSHIFT, sizeof(SEGMENT))) == NULL) {
+               save_errno = errno;
+               (void)hdestroy(hashp);
+               errno = save_errno;
+               return (-1);
+       }
+       for (i = 0; i < nsegs; i++, hashp->nsegs++)
+               hashp->dir[i] = &store[i << hashp->SSHIFT];
+       return (0);
+}
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+/*
+ * Hashp->hdr needs to be byteswapped.
+ */
+static void
+       HASHHDR *srcp, *destp;
+{
+       int i;
+
+       P_32_COPY(srcp->magic, destp->magic);
+       P_32_COPY(srcp->version, destp->version);
+       P_32_COPY(srcp->lorder, destp->lorder);
+       P_32_COPY(srcp->bsize, destp->bsize);
+       P_32_COPY(srcp->bshift, destp->bshift);
+       P_32_COPY(srcp->dsize, destp->dsize);
+       P_32_COPY(srcp->ssize, destp->ssize);
+       P_32_COPY(srcp->sshift, destp->sshift);
+       P_32_COPY(srcp->ovfl_point, destp->ovfl_point);
+       P_32_COPY(srcp->last_freed, destp->last_freed);
+       P_32_COPY(srcp->max_bucket, destp->max_bucket);
+       P_32_COPY(srcp->ffactor, destp->ffactor);
+       P_32_COPY(srcp->nkeys, destp->nkeys);
+       P_32_COPY(srcp->hdrpages, destp->hdrpages);
+       P_32_COPY(srcp->h_charkey, destp->h_charkey);
+       for (i = 0; i < NCACHED; i++) {
+               P_32_COPY(srcp->spares[i], destp->spares[i]);
+               P_16_COPY(srcp->bitmaps[i], destp->bitmaps[i]);
+       }
+}
+
+static void
+       HTAB *hashp;
+{
+       HASHHDR *hdrp;
+       int i;
+
+       hdrp = &hashp->hdr;
+
+       M_32_SWAP(hdrp->magic);
+       M_32_SWAP(hdrp->version);
+       M_32_SWAP(hdrp->lorder);
+       M_32_SWAP(hdrp->bsize);
+       M_32_SWAP(hdrp->bshift);
+       M_32_SWAP(hdrp->dsize);
+       M_32_SWAP(hdrp->ssize);
+       M_32_SWAP(hdrp->sshift);
+       M_32_SWAP(hdrp->ovfl_point);
+       M_32_SWAP(hdrp->last_freed);
+       M_32_SWAP(hdrp->max_bucket);
+       M_32_SWAP(hdrp->ffactor);
+       M_32_SWAP(hdrp->nkeys);
+       M_32_SWAP(hdrp->hdrpages);
+       M_32_SWAP(hdrp->h_charkey);
+       for (i = 0; i < NCACHED; i++) {
+               M_32_SWAP(hdrp->spares[i]);
+               M_16_SWAP(hdrp->bitmaps[i]);
+       }
+}
+#endif
diff --git a/db1-ast/hash/hash.h b/db1-ast/hash/hash.h
new file mode 100755 (executable)
index 0000000..d07db6f
--- /dev/null
@@ -0,0 +1,293 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *     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.
+ *
+ *     @(#)hash.h      8.3 (Berkeley) 5/31/94
+ */
+
+/* Operations */
+typedef enum {
+       HASH_GET, HASH_PUT, HASH_PUTNEW, HASH_DELETE, HASH_FIRST, HASH_NEXT
+} ACTION;
+
+/* Buffer Management structures */
+
+       char            *page;          /* Actual page data */
+       char            flags;
+#define        BUF_MOD         0x0001
+#define BUF_DISK       0x0002
+#define        BUF_BUCKET      0x0004
+#define        BUF_PIN         0x0008
+};
+
+#define IS_BUCKET(X)   ((X) & BUF_BUCKET)
+
+
+/* Hash Table Information */
+typedef struct hashhdr {               /* Disk resident portion */
+       int             magic;          /* Magic NO for hash tables */
+       int             version;        /* Version ID */
+       u_int32_t       lorder;         /* Byte Order */
+       int             bsize;          /* Bucket/Page Size */
+       int             bshift;         /* Bucket shift */
+       int             dsize;          /* Directory Size */
+       int             ssize;          /* Segment Size */
+       int             sshift;         /* Segment shift */
+       int             ovfl_point;     /* Where overflow pages are being
+                                        * allocated */
+       int             last_freed;     /* Last overflow page freed */
+       int             max_bucket;     /* ID of Maximum bucket in use */
+                                        * table */
+       int             ffactor;        /* Fill factor */
+       int             nkeys;          /* Number of keys in hash table */
+       int             hdrpages;       /* Size of table header */
+       int             h_charkey;      /* value of hash(CHARKEY) */
+#define NCACHED        32                      /* number of bit maps and spare
+                                        * points */
+       int             spares[NCACHED];/* spare pages for overflow */
+       u_int16_t       bitmaps[NCACHED];       /* address of overflow page
+                                                * bitmaps */
+} HASHHDR;
+
+typedef struct htab     {              /* Memory resident data structure */
+       HASHHDR         hdr;            /* Header */
+       int             nsegs;          /* Number of allocated segments */
+       int             exsegs;         /* Number of extra allocated
+                                        * segments */
+       u_int32_t                       /* Hash function */
+           (*hash)__P((const void *, size_t));
+       int             flags;          /* Flag values */
+       int             fp;             /* File pointer */
+       char            *tmp_buf;       /* Temporary Buffer for BIG data */
+       char            *tmp_key;       /* Temporary Buffer for BIG keys */
+       BUFHEAD         *cpage;         /* Current page */
+       int             cbucket;        /* Current bucket */
+       int             cndx;           /* Index of next item on cpage */
+       int             errnum;         /* Error Number -- for DBM
+                                        * compatibility */
+       int             new_file;       /* Indicates if fd is backing store
+                                        * or no */
+       int             save_file;      /* Indicates whether we need to flush
+                                        * file at
+                                        * exit */
+       u_int32_t       *mapp[NCACHED]; /* Pointers to page maps */
+       int             nmaps;          /* Initial number of bitmaps */
+       int             nbufs;          /* Number of buffers left to
+                                        * allocate */
+       SEGMENT         *dir;           /* Hash Bucket directory */
+} HTAB;
+
+/*
+ * Constants
+ */
+#define        MAX_BSIZE               65536           /* 2^16 */
+#define MIN_BUFFERS            6
+#define MINHDRSIZE             512
+#define DEF_BUFSIZE            65536           /* 64 K */
+#define DEF_BUCKET_SIZE                4096
+#define DEF_BUCKET_SHIFT       12              /* log2(BUCKET) */
+#define DEF_SEGSIZE            256
+#define DEF_SEGSIZE_SHIFT      8               /* log2(SEGSIZE)         */
+#define DEF_DIRSIZE            256
+#define DEF_FFACTOR            65536
+#define MIN_FFACTOR            4
+#define SPLTMAX                        8
+#define CHARKEY                        "%\$sniglet^&"
+#define NUMKEY                 1038583
+#define BYTE_SHIFT             3
+#define INT_TO_BYTE            2
+#define INT_BYTE_SHIFT         5
+#define ALL_SET                        ((u_int32_t)0xFFFFFFFF)
+#define ALL_CLEAR              0
+
+#define ISMOD(X)       ((u_int32_t)(ptrdiff_t)(X)&0x1)
+#define DOMOD(X)       ((X) = (char *)((ptrdiff_t)(X)|0x1))
+#define ISDISK(X)      ((u_int32_t)(ptrdiff_t)(X)&0x2)
+#define DODISK(X)      ((X) = (char *)((ptrdiff_t)(X)|0x2))
+
+#define BITS_PER_MAP   32
+
+/* Given the address of the beginning of a big map, clear/set the nth bit */
+#define CLRBIT(A, N)   ((A)[(N)/BITS_PER_MAP] &= ~(1<<((N)%BITS_PER_MAP)))
+#define SETBIT(A, N)   ((A)[(N)/BITS_PER_MAP] |= (1<<((N)%BITS_PER_MAP)))
+#define ISSET(A, N)    ((A)[(N)/BITS_PER_MAP] & (1<<((N)%BITS_PER_MAP)))
+
+/* Overflow management */
+/*
+ * Overflow page numbers are allocated per split point.  At each doubling of
+ * the table, we can allocate extra pages.  So, an overflow page number has
+ * the top 5 bits indicate which split point and the lower 11 bits indicate
+ * which page at that split point is indicated (pages within split points are
+ * numberered starting with 1).
+ */
+
+#define SPLITSHIFT     11
+#define SPLITNUM(N)    (((u_int32_t)(N)) >> SPLITSHIFT)
+#define        OADDR_OF(S,O)   ((u_int32_t)((u_int32_t)(S) << SPLITSHIFT) + (O))
+
+#define BUCKET_TO_PAGE(B) \
+       (B) + hashp->HDRPAGES + ((B) ? hashp->SPARES[__hash_log2((B)+1)-1] : 0)
+       BUCKET_TO_PAGE ( (1 << SPLITNUM((B))) -1 ) + OPAGENUM((B));
+
+/*
+ * page.h contains a detailed description of the page format.
+ *
+ * Normally, keys and data are accessed from offset tables in the top of
+ * each page which point to the beginning of the key and data.  There are
+ * four flag values which may be stored in these offset tables which indicate
+ * the following:
+ *
+ *
+ * OVFLPAGE    Rather than a key data pair, this pair contains
+ *             the address of an overflow page.  The format of
+ *             the pair is:
+ *                 OVERFLOW_PAGE_NUMBER OVFLPAGE
+ *
+ * PARTIAL_KEY This must be the first key/data pair on a page
+ *             and implies that page contains only a partial key.
+ *             That is, the key is too big to fit on a single page
+ *             so it starts on this page and continues on the next.
+ *             The format of the page is:
+ *                 KEY_OFF PARTIAL_KEY OVFL_PAGENO OVFLPAGE
+ *
+ *                 KEY_OFF -- offset of the beginning of the key
+ *                 PARTIAL_KEY -- 1
+ *                 OVFL_PAGENO - page number of the next overflow page
+ *                 OVFLPAGE -- 0
+ *
+ * FULL_KEY    This must be the first key/data pair on the page.  It
+ *             is used in two cases.
+ *
+ *             Case 1:
+ *                 There is a complete key on the page but no data
+ *                 (because it wouldn't fit).  The next page contains
+ *                 the data.
+ *
+ *                 Page format it:
+ *                 KEY_OFF FULL_KEY OVFL_PAGENO OVFL_PAGE
+ *
+ *                 KEY_OFF -- offset of the beginning of the key
+ *                 FULL_KEY -- 2
+ *                 OVFL_PAGENO - page number of the next overflow page
+ *                 OVFLPAGE -- 0
+ *
+ *             Case 2:
+ *                 This page contains no key, but part of a large
+ *                 data field, which is continued on the next page.
+ *
+ *                 Page format it:
+ *                 DATA_OFF FULL_KEY OVFL_PAGENO OVFL_PAGE
+ *
+ *                 KEY_OFF -- offset of the beginning of the data on
+ *                             this page
+ *                 FULL_KEY -- 2
+ *                 OVFL_PAGENO - page number of the next overflow page
+ *                 OVFLPAGE -- 0
+ *
+ * FULL_KEY_DATA
+ *             This must be the first key/data pair on the page.
+ *             There are two cases:
+ *
+ *             Case 1:
+ *                 This page contains a key and the beginning of the
+ *                 data field, but the data field is continued on the
+ *                 next page.
+ *
+ *                 Page format is:
+ *                 KEY_OFF FULL_KEY_DATA OVFL_PAGENO DATA_OFF
+ *
+ *                 KEY_OFF -- offset of the beginning of the key
+ *                 FULL_KEY_DATA -- 3
+ *                 OVFL_PAGENO - page number of the next overflow page
+ *                 DATA_OFF -- offset of the beginning of the data
+ *
+ *             Case 2:
+ *                 This page contains the last page of a big data pair.
+ *                 There is no key, only the  tail end of the data
+ *                 on this page.
+ *
+ *                 Page format is:
+ *                 DATA_OFF FULL_KEY_DATA <OVFL_PAGENO> <OVFLPAGE>
+ *
+ *                 DATA_OFF -- offset of the beginning of the data on
+ *                             this page
+ *                 FULL_KEY_DATA -- 3
+ *                 OVFL_PAGENO - page number of the next overflow page
+ *                 OVFLPAGE -- 0
+ *
+ *                 OVFL_PAGENO and OVFLPAGE are optional (they are
+ *                 not present if there is no next page).
+ */
+
+#define OVFLPAGE       0
+#define PARTIAL_KEY    1
+#define FULL_KEY       2
+#define FULL_KEY_DATA  3
+#define        REAL_KEY        4
+
+/* Short hands for accessing structure */
+#define BSIZE          hdr.bsize
+#define BSHIFT         hdr.bshift
+#define DSIZE          hdr.dsize
+#define SGSIZE         hdr.ssize
+#define SSHIFT         hdr.sshift
+#define LORDER         hdr.lorder
+#define OVFL_POINT     hdr.ovfl_point
+#define        LAST_FREED      hdr.last_freed
+#define MAX_BUCKET     hdr.max_bucket
+#define FFACTOR                hdr.ffactor
+#define NKEYS          hdr.nkeys
+#define HDRPAGES       hdr.hdrpages
+#define SPARES         hdr.spares
+#define BITMAPS                hdr.bitmaps
+#define VERSION                hdr.version
+#define MAGIC          hdr.magic
+#define NEXT_FREE      hdr.next_free
+#define H_CHARKEY      hdr.h_charkey
diff --git a/db1-ast/hash/hash_bigkey.c b/db1-ast/hash/hash_bigkey.c
new file mode 100755 (executable)
index 0000000..94c6408
--- /dev/null
@@ -0,0 +1,668 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *     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[] = "@(#)hash_bigkey.c      8.3 (Berkeley) 5/31/94";
+#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
+ */
+
+#include <sys/param.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef DEBUG
+#include <assert.h>
+#endif
+
+#include <db.h>
+#include "hash.h"
+#include "page.h"
+#include "extern.h"
+
+static int collect_key __P((HTAB *, BUFHEAD *, int, DBT *, int));
+static int collect_data __P((HTAB *, BUFHEAD *, int, int));
+
+/*
+ * Big_insert
+ *
+ * You need to do an insert and the key/data pair is too big
+ *
+ * Returns:
+ * 0 ==> OK
+ *-1 ==> ERROR
+ */
+extern int
+__big_insert(hashp, bufp, key, val)
+       HTAB *hashp;
+       const DBT *key, *val;
+{
+       register u_int16_t *p;
+       int key_size, n, val_size;
+       u_int16_t space, move_bytes, off;
+       char *cp, *key_data, *val_data;
+
+       cp = bufp->page;                /* Character pointer of p. */
+       p = (u_int16_t *)cp;
+
+       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;
+               memmove(cp + off, key_data, move_bytes);
+               key_size -= move_bytes;
+               key_data += move_bytes;
+               n = p;
+               p[++n] = off;
+               p = ++n;
+               FREESPACE(p) = off - PAGE_META(n);
+               OFFSET(p) = off;
+               p[n] = PARTIAL_KEY;
+               if (!bufp)
+                       return (-1);
+               n = p;
+               if (!key_size) {
+                       if (FREESPACE(p)) {
+                               move_bytes = MIN(FREESPACE(p), val_size);
+                               off = OFFSET(p) - move_bytes;
+                               p[n] = off;
+                               memmove(cp + off, val_data, 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_int16_t *)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 ((int) space == val_size && (size_t) val_size == val->size)
+                       move_bytes--;
+               off = OFFSET(p) - move_bytes;
+               memmove(cp + off, val_data, move_bytes);
+               val_size -= move_bytes;
+               val_data += move_bytes;
+               n = p;
+               p[++n] = off;
+               p = ++n;
+               FREESPACE(p) = off - PAGE_META(n);
+               OFFSET(p) = off;
+               if (val_size) {
+                       p[n] = FULL_KEY;
+                       if (!bufp)
+                               return (-1);
+                       cp = bufp->page;
+                       p = (u_int16_t *)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(hashp, bufp)
+       HTAB *hashp;
+{
+       u_int16_t *bp, pageno;
+       int key_done, n;
+
+       rbufp = bufp;
+       last_bfp = NULL;
+       bp = (u_int16_t *)bufp->page;
+       pageno = 0;
+       key_done = 0;
+
+       while (!key_done || (bp != FULL_KEY_DATA)) {
+               if (bp == FULL_KEY || bp == 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 == FULL_KEY_DATA && FREESPACE(bp))
+                       break;
+               pageno = bp[bp - 1];
+               rbufp->flags |= BUF_MOD;
+               rbufp = __get_buf(hashp, pageno, rbufp, 0);
+               if (last_bfp)
+                       __free_ovflpage(hashp, last_bfp);
+               last_bfp = rbufp;
+               if (!rbufp)
+                       return (-1);            /* Error. */
+               bp = (u_int16_t *)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;
+       pageno = bp[n - 1];
+
+       /* Now, bp is the first page of the pair. */
+       bp = (u_int16_t *)bufp->page;
+       if (n > 2) {
+               /* There is an overflow page. */
+               bp = pageno;
+               bp = OVFLPAGE;
+               bufp->ovfl = rbufp->ovfl;
+       } else
+               /* This is the last page. */
+               bufp->ovfl = NULL;
+       n -= 2;
+       bp = n;
+       FREESPACE(bp) = hashp->BSIZE - PAGE_META(n);
+       OFFSET(bp) = hashp->BSIZE - 1;
+
+       bufp->flags |= BUF_MOD;
+       if (rbufp)
+               __free_ovflpage(hashp, rbufp);
+       if (last_bfp && last_bfp != rbufp)
+               __free_ovflpage(hashp, last_bfp);
+
+       hashp->NKEYS--;
+       return (0);
+}
+/*
+ * Returns:
+ *  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(hashp, bufp, ndx, key, size)
+       HTAB *hashp;
+       int ndx;
+       char *key;
+       int size;
+{
+       register u_int16_t *bp;
+       register char *p;
+       int ksize;
+       u_int16_t bytes;
+       char *kkey;
+
+       bp = (u_int16_t *)bufp->page;
+       p = bufp->page;
+       ksize = size;
+       kkey = key;
+
+       for (bytes = hashp->BSIZE - bp[ndx];
+           bytes <= size && bp[ndx + 1] == PARTIAL_KEY;
+           bytes = hashp->BSIZE - bp[ndx]) {
+               if (memcmp(p + bp[ndx], kkey, bytes))
+                       return (-2);
+               kkey += bytes;
+               ksize -= bytes;
+               bufp = __get_buf(hashp, bp[ndx + 2], bufp, 0);
+               if (!bufp)
+                       return (-3);
+               p = bufp->page;
+               bp = (u_int16_t *)p;
+               ndx = 1;
+       }
+
+       if (bytes != ksize || memcmp(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_int16_t
+__find_last_page(hashp, bpp)
+       HTAB *hashp;
+{
+       u_int16_t *bp, pageno;
+       int n;
+
+       bufp = *bpp;
+       bp = (u_int16_t *)bufp->page;
+       for (;;) {
+               n = bp;
+
+               /*
+                * 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 == FULL_KEY_DATA &&
+                   ((n == 2) || (bp[n] == OVFLPAGE) || (FREESPACE(bp))))
+                       break;
+
+               pageno = bp[n - 1];
+               bufp = __get_buf(hashp, pageno, bufp, 0);
+               if (!bufp)
+                       return (0);     /* Need to indicate an error! */
+               bp = (u_int16_t *)bufp->page;
+       }
+
+       *bpp = bufp;
+       if (bp > 2)
+               return (bp);
+       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(hashp, bufp, ndx, val, set_current)
+       HTAB *hashp;
+       int ndx;
+       DBT *val;
+       int set_current;
+{
+       u_int16_t *bp, len, off, save_addr;
+       char *tp;
+
+       bp = (u_int16_t *)bufp->page;
+       while (bp[ndx + 1] == PARTIAL_KEY) {
+               bufp = __get_buf(hashp, bp[bp - 1], bufp, 0);
+               if (!bufp)
+                       return (-1);
+               bp = (u_int16_t *)bufp->page;
+               ndx = 1;
+       }
+
+       if (bp[ndx + 1] == FULL_KEY) {
+               bufp = __get_buf(hashp, bp[bp - 1], bufp, 0);
+               if (!bufp)
+                       return (-1);
+               bp = (u_int16_t *)bufp->page;
+               save_p = bufp;
+               off = bp;
+               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];
+                       len = bp - off;
+                       save_p = bufp;
+                       bufp = __get_buf(hashp, bp[bp - 1], bufp, 0);
+                       if (!bufp)
+                               return (-1);
+                       bp = (u_int16_t *)bufp->page;
+               } else {
+                       /* The data is all on one page. */
+                       tp = (char *)bp;
+                       off = bp[bp];
+                       val->data = (u_char *)tp + off;
+                       val->size = bp - off;
+                       if (set_current) {
+                               if (bp == 2) {       /* No more buckets in
+                                                        * chain */
+                                       hashp->cpage = NULL;
+                                       hashp->cbucket++;
+                                       hashp->cndx = 1;
+                               } else {
+                                       hashp->cpage = __get_buf(hashp,
+                                           bp[bp - 1], bufp, 0);
+                                       if (!hashp->cpage)
+                                               return (-1);
+                                       hashp->cndx = 1;
+                                       if (!((u_int16_t *)
+                                           hashp->cpage->page)) {
+                                               hashp->cbucket++;
+                                               hashp->cpage = NULL;
+                                       }
+                               }
+                       }
+                       return (0);
+               }
+
+       val->size = collect_data(hashp, bufp, (int)len, set_current);
+       if (val->size == (size_t) -1)
+               return (-1);
+               /* We are pretty short on buffers. */
+               errno = EINVAL;                 /* OUT OF BUFFERS */
+               return (-1);
+       }
+       memmove(hashp->tmp_buf, (save_p->page) + off, 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(hashp, bufp, len, set)
+       HTAB *hashp;
+       int len, set;
+{
+       register u_int16_t *bp;
+       register char *p;
+       int mylen, totlen;
+
+       p = bufp->page;
+       bp = (u_int16_t *)p;
+       mylen = hashp->BSIZE - bp;
+
+       if (bp == FULL_KEY_DATA) {           /* End of Data */
+               totlen = len + mylen;
+               if (hashp->tmp_buf)
+                       free(hashp->tmp_buf);
+               if ((hashp->tmp_buf = (char *)malloc(totlen)) == NULL)
+                       return (-1);
+               if (set) {
+                       hashp->cndx = 1;
+                       if (bp == 2) {       /* No more buckets in chain */
+                               hashp->cpage = NULL;
+                               hashp->cbucket++;
+                       } else {
+                               hashp->cpage =
+                                   __get_buf(hashp, bp[bp - 1], bufp, 0);
+                               if (!hashp->cpage)
+                                       return (-1);
+                               else if (!((u_int16_t *)hashp->cpage->page)) {
+                                       hashp->cbucket++;
+                                       hashp->cpage = NULL;
+                               }
+                       }
+               }
+       } else {
+               xbp = __get_buf(hashp, bp[bp - 1], bufp, 0);
+               if (!xbp || ((totlen =
+                   collect_data(hashp, xbp, len + mylen, set)) < 1))
+                       return (-1);
+       }
+               errno = EINVAL;                 /* Out of buffers. */
+               return (-1);
+       }
+       memmove(&hashp->tmp_buf[len], (bufp->page) + bp, mylen);
+       return (totlen);
+}
+
+/*
+ * Fill in the key and data for this big pair.
+ */
+extern int
+__big_keydata(hashp, bufp, key, val, set)
+       HTAB *hashp;
+       DBT *key, *val;
+       int set;
+{
+       key->size = collect_key(hashp, bufp, 0, val, set);
+       if (key->size == (size_t) -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(hashp, bufp, len, val, set)
+       HTAB *hashp;
+       int len;
+       DBT *val;
+       int set;
+{
+       char *p;
+       int mylen, totlen;
+
+       p = bufp->page;
+       bp = (u_int16_t *)p;
+       mylen = hashp->BSIZE - bp;
+
+       totlen = len + mylen;
+       if (bp == FULL_KEY || bp == FULL_KEY_DATA) {    /* End of Key. */
+               if (hashp->tmp_key != NULL)
+                       free(hashp->tmp_key);
+               if ((hashp->tmp_key = (char *)malloc(totlen)) == NULL)
+                       return (-1);
+               if (__big_return(hashp, bufp, 1, val, set))
+                       return (-1);
+       } else {
+               xbp = __get_buf(hashp, bp[bp - 1], bufp, 0);
+               if (!xbp || ((totlen =
+                   collect_key(hashp, xbp, totlen, val, set)) < 1))
+                       return (-1);
+       }
+               errno = EINVAL;         /* MIS -- OUT OF BUFFERS */
+               return (-1);
+       }
+       memmove(&hashp->tmp_key[len], (bufp->page) + bp, mylen);
+       return (totlen);
+}
+
+/*
+ * Returns:
+ *  0 => OK
+ * -1 => error
+ */
+extern int
+__big_split(hashp, op, np, big_keyp, addr, obucket, ret)
+       HTAB *hashp;
+       BUFHEAD *op;    /* Pointer to where to put keys that go in old bucket */
+       BUFHEAD *np;    /* Pointer to new bucket page */
+                       /* Pointer to first page containing the big key/data */
+       u_int32_t   obucket;/* Old Bucket */
+       SPLIT_RETURN *ret;
+{
+       register u_int16_t *tp;
+       DBT key, val;
+       u_int32_t change;
+       u_int16_t free_space, n, off;
+
+       bp = big_keyp;
+
+       /* Now figure out where the big key/data goes */
+       if (__big_keydata(hashp, big_keyp, &key, &val, 0))
+               return (-1);
+       change = (__call_hash(hashp, key.data, key.size) != obucket);
+
+       if ((ret->next_addr = __find_last_page(hashp, &big_keyp))) {
+               if (!(ret->nextp =
+                       return (-1);;
+       } else
+               ret->nextp = NULL;
+
+       /* Now make one of np/op point to the big key/data pair */
+#ifdef DEBUG
+       assert(np->ovfl == NULL);
+#endif
+       if (change)
+               tmpp = np;
+       else
+               tmpp = op;
+
+       tmpp->flags |= BUF_MOD;
+#ifdef DEBUG1
+       (void)fprintf(stderr,
+           "BIG_SPLIT: %d->ovfl was %d is now %d\n", tmpp->addr,
+#endif
+       tmpp->ovfl = bp;        /* one of op/np point to big_keyp */
+       tp = (u_int16_t *)tmpp->page;
+#ifdef DEBUG
+       assert(FREESPACE(tp) >= OVFLSIZE);
+#endif
+       n = tp;
+       off = OFFSET(tp);
+       free_space = FREESPACE(tp);
+       tp[++n] = OVFLPAGE;
+       tp = 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_int16_t *)big_keyp->page;
+       big_keyp->flags |= BUF_MOD;
+       if (tp > 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 is OVFLPAGE.  If there are two, tp contains
+                * the second offset and needs to get stuffed in after the
+                * next overflow page is added.
+                */
+               n = tp;
+               free_space = FREESPACE(tp);
+               off = OFFSET(tp);
+               tp -= 2;
+               FREESPACE(tp) = free_space + OVFLSIZE;
+               OFFSET(tp) = off;
+               if (!tmpp)
+                       return (-1);
+               tp = n;
+       } else
+               tmpp = big_keyp;
+
+       if (change)
+               ret->newp = tmpp;
+       else
+               ret->oldp = tmpp;
+       return (0);
+}
diff --git a/db1-ast/hash/hash_buf.c b/db1-ast/hash/hash_buf.c
new file mode 100755 (executable)
index 0000000..92e1f93
--- /dev/null
@@ -0,0 +1,355 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *     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[] = "@(#)hash_buf.c 8.5 (Berkeley) 7/15/94";
+#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 <errno.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef DEBUG
+#include <assert.h>
+#endif
+
+#include <db.h>
+#include "hash.h"
+#include "page.h"
+#include "extern.h"
+
+
+/* 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 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.
+ */
+       HTAB *hashp;
+       int newpage;    /* If prev_bp set, indicates a new overflow page. */
+{
+       register int is_disk, segment_ndx;
+       SEGMENT segp;
+
+       is_disk = 0;
+       if (prev_bp) {
+               bp = prev_bp->ovfl;
+                       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 = is_disk_mask || !hashp->new_file;
+       }
+
+       if (!bp) {
+               bp = newbuf(hashp, addr, prev_bp);
+               if (!bp ||
+                   __get_page(hashp, bp->page, addr, !prev_bp, is_disk, 0))
+                       return (NULL);
+               if (!prev_bp)
+                       segp[segment_ndx] =
+       } 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.
+ */
+       HTAB *hashp;
+{
+       register BUFHEAD *bp;           /* The buffer we're going to use */
+       register BUFHEAD *xbp;          /* Temp pointer */
+       SEGMENT segp;
+       int segment_ndx;
+
+       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 */
+                       return (NULL);
+#ifdef PURIFY
+#endif
+               if ((bp->page = (char *)malloc(hashp->BSIZE)) == NULL) {
+                       free(bp);
+                       return (NULL);
+               }
+#ifdef PURIFY
+               memset(bp->page, 0xff, hashp->BSIZE);
+#endif
+               if (hashp->nbufs)
+                       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_int16_t *)bp->page;
+                       if (shortp)
+                               oaddr = shortp[shortp - 1];
+                       if ((bp->flags & BUF_MOD) && __put_page(hashp, bp->page,
+                               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];
+#ifdef DEBUG
+                               assert(segp != NULL);
+#endif
+
+                               if (hashp->new_file &&
+                                   ((bp->flags & BUF_MOD) ||
+                                   ISDISK(segp[segment_ndx])))
+                               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) ||
+                                       break;
+
+                               shortp = (u_int16_t *)xbp->page;
+                               if (shortp)
+                                       /* set before __put_page */
+                                       oaddr = shortp[shortp - 1];
+                               if ((xbp->flags & BUF_MOD) && __put_page(hashp,
+                                       return (NULL);
+                               xbp->flags = 0;
+                               BUF_REMOVE(xbp);
+                               LRU_INSERT(xbp);
+                       }
+               }
+       }
+
+       /* Now assign this buffer */
+#ifdef DEBUG1
+       (void)fprintf(stderr, "NEWBUF1: %d->ovfl was %d is now %d\n",
+#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
+               (void)fprintf(stderr, "NEWBUF2: %d->ovfl was %d is now %d\n",
+                   (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(hashp, nbytes)
+       HTAB *hashp;
+       int nbytes;
+{
+       int npages;
+
+       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;
+        */
+}
+
+extern int
+__buf_free(hashp, do_free, to_disk)
+       HTAB *hashp;
+       int do_free, to_disk;
+{
+
+       /* 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(hashp, bp->page,
+                               return (-1);
+               }
+               /* Check if we are freeing stuff */
+               if (do_free) {
+                       if (bp->page)
+                               free(bp->page);
+                       BUF_REMOVE(bp);
+                       free(bp);
+                       bp = LRU;
+               } else
+                       bp = bp->prev;
+       }
+       return (0);
+}
+
+extern void
+__reclaim_buf(hashp, bp)
+       HTAB *hashp;
+{
+       bp->ovfl = 0;
+       bp->flags = 0;
+       BUF_REMOVE(bp);
+       LRU_INSERT(bp);
+}
diff --git a/db1-ast/hash/hash_func.c b/db1-ast/hash/hash_func.c
new file mode 100755 (executable)
index 0000000..a5ec434
--- /dev/null
@@ -0,0 +1,212 @@
+/*-
+ * Copyright (c) 1990, 1993
+ *     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[] = "@(#)hash_func.c        8.2 (Berkeley) 2/21/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+
+#include <db.h>
+#include "hash.h"
+#include "page.h"
+#include "extern.h"
+
+static u_int32_t hash1 __P((const void *, size_t));
+static u_int32_t hash2 __P((const void *, size_t));
+static u_int32_t hash3 __P((const void *, size_t));
+static u_int32_t hash4 __P((const void *, size_t));
+
+/* Global default hash function */
+u_int32_t (*__default_hash) __P((const void *, size_t)) = hash4;
+
+/*
+ * HASH FUNCTIONS
+ *
+ * Assume that we've already split the bucket to which this key hashes,
+ * calculate that bucket, and check that in fact we did already split it.
+ *
+ * This came from ejb's hsearch.
+ */
+
+#define PRIME1         37
+#define PRIME2         1048583
+
+static u_int32_t
+hash1(keyarg, len)
+       const void *keyarg;
+       register size_t len;
+{
+       register const u_char *key;
+       register u_int32_t h;
+
+       /* Convert string to integer */
+       for (key = keyarg, h = 0; len--;)
+               h = h * PRIME1 ^ (*key++ - ' ');
+       h %= PRIME2;
+       return (h);
+}
+
+/*
+ * Phong's linear congruential hash
+ */
+#define dcharhash(h, c)        ((h) = 0x63c63cd9*(h) + 0x9c39c33d + (c))
+
+static u_int32_t
+hash2(keyarg, len)
+       const void *keyarg;
+       size_t len;
+{
+       register const u_char *e, *key;
+       register u_int32_t h;
+       register u_char c;
+
+       key = keyarg;
+       e = key + len;
+       for (h = 0; key != e;) {
+               c = *key++;
+               if (!c && key > e)
+                       break;
+               dcharhash(h, c);
+       }
+       return (h);
+}
+
+/*
+ * This is INCREDIBLY ugly, but fast.  We break the string up into 8 byte
+ * units.  On the first time through the loop we get the "leftover bytes"
+ * (strlen % 8).  On every other iteration, we perform 8 HASHC's so we handle
+ * all 8 bytes.  Essentially, this saves us 7 cmp & branch instructions.  If
+ * this routine is heavily used enough, it's worth the ugly coding.
+ *
+ * OZ's original sdbm hash
+ */
+static u_int32_t
+hash3(keyarg, len)
+       const void *keyarg;
+       register size_t len;
+{
+       register const u_char *key;
+       register size_t loop;
+       register u_int32_t h;
+
+#define HASHC   h = *key++ + 65599 * h
+
+       h = 0;
+       key = keyarg;
+       if (len > 0) {
+               loop = (len + 8 - 1) >> 3;
+
+               switch (len & (8 - 1)) {
+               case 0:
+                       do {
+                               HASHC;
+                               /* FALLTHROUGH */
+               case 7:
+                               HASHC;
+                               /* FALLTHROUGH */
+               case 6:
+                               HASHC;
+                               /* FALLTHROUGH */
+               case 5:
+                               HASHC;
+                               /* FALLTHROUGH */
+               case 4:
+                               HASHC;
+                               /* FALLTHROUGH */
+               case 3:
+                               HASHC;
+                               /* FALLTHROUGH */
+               case 2:
+                               HASHC;
+                               /* FALLTHROUGH */
+               case 1:
+                               HASHC;
+                       } while (--loop);
+               }
+       }
+       return (h);
+}
+
+/* Hash function from Chris Torek. */
+static u_int32_t
+hash4(keyarg, len)
+       const void *keyarg;
+       register size_t len;
+{
+       register const u_char *key;
+       register size_t loop;
+       register u_int32_t h;
+
+#define HASH4a   h = (h << 5) - h + *key++;
+#define HASH4b   h = (h << 5) + h + *key++;
+#define HASH4 HASH4b
+
+       h = 0;
+       key = keyarg;
+       if (len > 0) {
+               loop = (len + 8 - 1) >> 3;
+
+               switch (len & (8 - 1)) {
+               case 0:
+                       do {
+                               HASH4;
+                               /* FALLTHROUGH */
+               case 7:
+                               HASH4;
+                               /* FALLTHROUGH */
+               case 6:
+                               HASH4;
+                               /* FALLTHROUGH */
+               case 5:
+                               HASH4;
+                               /* FALLTHROUGH */
+               case 4:
+                               HASH4;
+                               /* FALLTHROUGH */
+               case 3:
+                               HASH4;
+                               /* FALLTHROUGH */
+               case 2:
+                               HASH4;
+                               /* FALLTHROUGH */
+               case 1:
+                               HASH4;
+                       } while (--loop);
+               }
+       }
+       return (h);
+}
diff --git a/db1-ast/hash/hash_log2.c b/db1-ast/hash/hash_log2.c
new file mode 100755 (executable)
index 0000000..6bcf9c1
--- /dev/null
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *     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[] = "@(#)hash_log2.c        8.2 (Berkeley) 5/31/94";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+
+#include <db.h>
+
+u_int32_t __hash_log2 __P((u_int32_t));
+
+u_int32_t
+__hash_log2(num)
+       u_int32_t num;
+{
+       register u_int32_t i, limit;
+
+       limit = 1;
+       for (i = 0; limit < num; limit = limit << 1, i++);
+       return (i);
+}
diff --git a/db1-ast/hash/hash_page.c b/db1-ast/hash/hash_page.c
new file mode 100755 (executable)
index 0000000..e1dfe6b
--- /dev/null
@@ -0,0 +1,944 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ *     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 Univ
{"ft_lang_label":"__label__en","ft_lang_prob":0.5631169,"math_prob":0.9318528,"size":213852,"snap":"2022-05-2022-21","text_gpt3_token_len":68170,"char_repetition_ratio":0.15554506,"word_repetition_ratio":0.44154984,"special_character_ratio":0.3802209,"punctuation_ratio":0.1961075,"nsfw_num_words":0,"has_unicode_error":false,"math_prob_llama3":0.9648403,"pos_list":[0],"im_url_duplicate_count":[null],"WARC_HEADER":"{\"WARC-Type\":\"response\",\"WARC-Date\":\"2022-05-22T01:09:42Z\",\"WARC-Record-ID\":\"<urn:uuid:68a3bfc5-2955-4373-9e79-292d7c54d267>\",\"Content-Length\":\"1048875\",\"Content-Type\":\"application/http; msgtype=response\",\"WARC-Warcinfo-ID\":\"<urn:uuid:8121b50e-27e5-4c32-ae61-922a38f79474>\",\"WARC-Concurrent-To\":\"<urn:uuid:59017434-754a-49ec-840e-36bec81c9a56>\",\"WARC-IP-Address\":\"170.249.154.172\",\"WARC-Target-URI\":\"https://git.asterisk.org/gitweb/?p=asterisk/asterisk.git;a=commitdiff;h=aeb89d9744f30cdf1f674ac9399cb8111e8af451\",\"WARC-Payload-Digest\":\"sha1:VVTEQM5SB3RZFQJFLECV53YXS4SRWUQO\",\"WARC-Block-Digest\":\"sha1:SAV2WDVTX3AHXELUGKQGVAATFXIIYMSZ\",\"WARC-Truncated\":\"length\",\"WARC-Identified-Payload-Type\":\"application/xhtml+xml\",\"warc_filename\":\"/cc_download/warc_2022/CC-MAIN-2022-21/CC-MAIN-2022-21_segments_1652662543264.49_warc_CC-MAIN-20220522001016-20220522031016-00577.warc.gz\"}"}