Update from db 2.4.14.
authordrepper <drepper>
Tue, 9 Jun 1998 15:02:06 +0000 (15:02 +0000)
committerdrepper <drepper>
Tue, 9 Jun 1998 15:02:06 +0000 (15:02 +0000)
139 files changed:
db2/btree/bt_close.c
db2/btree/bt_compare.c
db2/btree/bt_conv.c
db2/btree/bt_cursor.c
db2/btree/bt_delete.c
db2/btree/bt_open.c
db2/btree/bt_page.c
db2/btree/bt_put.c
db2/btree/bt_rec.c
db2/btree/bt_recno.c
db2/btree/bt_rsearch.c
db2/btree/bt_search.c
db2/btree/bt_split.c
db2/btree/bt_stat.c
db2/btree/btree.src
db2/btree/btree_auto.c
db2/clib/getlong.c
db2/common/db_appinit.c
db2/common/db_apprec.c
db2/common/db_byteorder.c
db2/common/db_err.c
db2/common/db_log2.c
db2/common/db_region.c
db2/common/db_salloc.c
db2/common/db_shash.c
db2/config.h
db2/db.h
db2/db/db.c
db2/db/db.src
db2/db/db_auto.c
db2/db/db_conv.c
db2/db/db_dispatch.c
db2/db/db_dup.c
db2/db/db_overflow.c
db2/db/db_pr.c
db2/db/db_rec.c
db2/db/db_ret.c
db2/db/db_thread.c
db2/db185/db185.c
db2/db185/db185_int.h
db2/db_185.h
db2/db_int.h
db2/dbm/dbm.c
db2/hash/hash.c
db2/hash/hash.src
db2/hash/hash_auto.c
db2/hash/hash_conv.c
db2/hash/hash_debug.c
db2/hash/hash_dup.c
db2/hash/hash_func.c
db2/hash/hash_page.c
db2/hash/hash_rec.c
db2/hash/hash_stat.c
db2/include/btree.h
db2/include/btree_ext.h
db2/include/clib_ext.h
db2/include/common_ext.h
db2/include/cxx_int.h
db2/include/db.h.src
db2/include/db_185.h.src
db2/include/db_am.h
db2/include/db_auto.h
db2/include/db_cxx.h
db2/include/db_dispatch.h
db2/include/db_ext.h
db2/include/db_int.h.src
db2/include/db_page.h
db2/include/db_shash.h
db2/include/db_swap.h
db2/include/hash.h
db2/include/hash_ext.h
db2/include/lock.h
db2/include/lock_ext.h
db2/include/log.h
db2/include/log_ext.h
db2/include/mp.h
db2/include/mp_ext.h
db2/include/mutex_ext.h
db2/include/os_ext.h
db2/include/os_func.h
db2/include/queue.h
db2/include/shqueue.h
db2/include/txn.h
db2/lock/lock.c
db2/lock/lock_conflict.c
db2/lock/lock_deadlock.c
db2/lock/lock_util.c
db2/log/log.c
db2/log/log.src
db2/log/log_archive.c
db2/log/log_auto.c
db2/log/log_compare.c
db2/log/log_findckp.c
db2/log/log_get.c
db2/log/log_put.c
db2/log/log_rec.c
db2/log/log_register.c
db2/mp/mp_bh.c
db2/mp/mp_fget.c
db2/mp/mp_fopen.c
db2/mp/mp_fput.c
db2/mp/mp_fset.c
db2/mp/mp_open.c
db2/mp/mp_pr.c
db2/mp/mp_region.c
db2/mp/mp_sync.c
db2/mutex/68020.gcc
db2/mutex/mutex.c
db2/mutex/parisc.gcc
db2/mutex/parisc.hp
db2/os/os_abs.c
db2/os/os_alloc.c
db2/os/os_config.c
db2/os/os_dir.c
db2/os/os_fid.c
db2/os/os_fsync.c
db2/os/os_map.c
db2/os/os_oflags.c
db2/os/os_open.c
db2/os/os_rpath.c
db2/os/os_rw.c
db2/os/os_seek.c
db2/os/os_sleep.c
db2/os/os_spin.c
db2/os/os_stat.c
db2/os/os_unlink.c
db2/progs/db_archive/db_archive.c
db2/progs/db_checkpoint/db_checkpoint.c
db2/progs/db_deadlock/db_deadlock.c
db2/progs/db_dump/db_dump.c
db2/progs/db_dump185/db_dump185.c
db2/progs/db_load/db_load.c
db2/progs/db_printlog/db_printlog.c
db2/progs/db_recover/db_recover.c
db2/progs/db_stat/db_stat.c
db2/txn/txn.c
db2/txn/txn.src
db2/txn/txn_auto.c
db2/txn/txn_rec.c

index ecccc9f..9df5c71 100644 (file)
@@ -1,7 +1,7 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 1996, 1997
+ * Copyright (c) 1996, 1997, 1998
  *     Sleepycat Software.  All rights reserved.
  */
 /*
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)bt_close.c   10.25 (Sleepycat) 1/6/98";
+static const char sccsid[] = "@(#)bt_close.c   10.32 (Sleepycat) 5/6/98";
 #endif /* not lint */
 
 #ifndef NO_SYSTEM_INCLUDES
 #include <sys/types.h>
-#include <sys/mman.h>
 
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
 #include <string.h>
-#include <unistd.h>
 #endif
 
 #include "db_int.h"
@@ -104,12 +99,12 @@ __bam_close(dbp)
  * __bam_sync --
  *     Sync the btree to disk.
  *
- * PUBLIC: int __bam_sync __P((DB *, int));
+ * PUBLIC: int __bam_sync __P((DB *, u_int32_t));
  */
 int
 __bam_sync(argdbp, flags)
        DB *argdbp;
-       int flags;
+       u_int32_t flags;
 {
        DB *dbp;
        int ret;
@@ -146,7 +141,7 @@ __bam_upstat(dbp)
        BTMETA *meta;
        DB_LOCK metalock;
        db_pgno_t pgno;
-       int flags, ret;
+       u_int32_t flags;
 
        /*
         * We use a no-op log call to log the update of the statistics onto the
@@ -166,8 +161,8 @@ __bam_upstat(dbp)
        if (__bam_pget(dbp, (PAGE **)&meta, &pgno, 0) == 0) {
                /* Log the change. */
                if (DB_LOGGING(dbp) &&
-                   (ret = __db_noop_log(dbp->dbenv->lg_info, dbp->txn,
-                   &LSN(meta), 0)) == 0)
+                   __db_noop_log(dbp->dbenv->lg_info, dbp->txn, &LSN(meta), 0,
+                   dbp->log_fileid, PGNO_METADATA, &LSN(meta)) != 0)
                        goto err;
 
                /* Update the statistics. */
index a68b1fa..5c6d1e3 100644 (file)
@@ -1,7 +1,7 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 1996, 1997
+ * Copyright (c) 1996, 1997, 1998
  *     Sleepycat Software.  All rights reserved.
  */
 /*
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)bt_compare.c 10.4 (Sleepycat) 9/3/97";
+static const char sccsid[] = "@(#)bt_compare.c 10.9 (Sleepycat) 5/6/98";
 #endif /* not lint */
 
 #ifndef NO_SYSTEM_INCLUDES
 #include <sys/types.h>
 
-#include <stdio.h>
-#include <stdlib.h>
 #include <string.h>
 #endif
 
@@ -106,7 +104,6 @@ __bam_cmp(dbp, k1, e)
                if (B_TYPE(bk->type) == B_OVERFLOW)
                        bo = (BOVERFLOW *)bk;
                else {
-                       memset(&k2, 0, sizeof(k2));
                        k2.data = bk->data;
                        k2.size = bk->len;
                }
@@ -115,7 +112,6 @@ __bam_cmp(dbp, k1, e)
                if (B_TYPE(bi->type) == B_OVERFLOW)
                        bo = (BOVERFLOW *)(bi->data);
                else {
-                       memset(&k2, 0, sizeof(k2));
                        k2.data = bi->data;
                        k2.size = bi->len;
                }
@@ -139,10 +135,21 @@ __bam_cmp(dbp, k1, e)
                 * Otherwise, we need a contiguous record so we can hand it
                 * to the user's routine.
                 */
+               memset(&k2, 0, sizeof(k2));
                if (__db_goff(dbp, &k2, bo->tlen,
-                   bo->pgno, &t->bt_rdata.data, &t->bt_rdata.ulen) != 0)
-                       abort();
+                   bo->pgno, &t->bt_rdata.data, &t->bt_rdata.ulen) != 0) {
+                       (void)__db_panic(dbp);
+                       return (0);
+               }
        }
+
+       /*
+        * XXX
+        * Note, we have not cleared the k2 DBT in this path.  This should
+        * be okay, because the user's comparison routine had better not be
+        * looking at any fields other than the data/size.  We don't clear
+        * it because we go through this path a lot and it's expensive.
+        */
        return ((*t->bt_compare)(k1, &k2));
 }
 
index c89493c..3da4507 100644 (file)
@@ -1,14 +1,14 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 1996, 1997
+ * Copyright (c) 1996, 1997, 1998
  *     Sleepycat Software.  All rights reserved.
  */
 
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)bt_conv.c    10.5 (Sleepycat) 9/15/97";
+static const char sccsid[] = "@(#)bt_conv.c    10.6 (Sleepycat) 4/10/98";
 #endif /* not lint */
 
 #ifndef NO_SYSTEM_INCLUDES
index f526c96..cfa3887 100644 (file)
@@ -1,22 +1,20 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 1996, 1997
+ * Copyright (c) 1996, 1997, 1998
  *     Sleepycat Software.  All rights reserved.
  */
 
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)bt_cursor.c  10.41 (Sleepycat) 1/8/98";
+static const char sccsid[] = "@(#)bt_cursor.c  10.53 (Sleepycat) 5/25/98";
 #endif /* not lint */
 
 #ifndef NO_SYSTEM_INCLUDES
 #include <sys/types.h>
 
 #include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
 #include <string.h>
 #endif
 
@@ -25,24 +23,30 @@ static const char sccsid[] = "@(#)bt_cursor.c       10.41 (Sleepycat) 1/8/98";
 #include "btree.h"
 
 static int __bam_c_close __P((DBC *));
-static int __bam_c_del __P((DBC *, int));
+static int __bam_c_del __P((DBC *, u_int32_t));
 static int __bam_c_first __P((DB *, CURSOR *));
-static int __bam_c_get __P((DBC *, DBT *, DBT *, int));
+static int __bam_c_get __P((DBC *, DBT *, DBT *, u_int32_t));
+static int __bam_c_getstack __P((DB *, CURSOR *));
 static int __bam_c_last __P((DB *, CURSOR *));
 static int __bam_c_next __P((DB *, CURSOR *, int));
 static int __bam_c_physdel __P((DB *, CURSOR *, PAGE *));
 static int __bam_c_prev __P((DB *, CURSOR *));
-static int __bam_c_put __P((DBC *, DBT *, DBT *, int));
-static int __bam_c_rget __P((DB *, CURSOR *, DBT *, int));
-static int __bam_c_search __P((DB *, CURSOR *, const DBT *, u_int, int, int *));
+static int __bam_c_put __P((DBC *, DBT *, DBT *, u_int32_t));
+static int __bam_c_rget __P((DB *, CURSOR *, DBT *, u_int32_t));
+static int __bam_c_search
+              __P((DB *, CURSOR *, const DBT *, u_int32_t, int, int *));
 
 /* Discard the current page/lock held by a cursor. */
 #undef DISCARD
 #define        DISCARD(dbp, cp) {                                              \
-       (void)memp_fput(dbp->mpf, (cp)->page, 0);                       \
-       (cp)->page = NULL;                                              \
-       (void)__BT_TLPUT((dbp), (cp)->lock);                            \
-       (cp)->lock = LOCK_INVALID;                                      \
+       if ((cp)->page != NULL) {                                       \
+               (void)memp_fput(dbp->mpf, (cp)->page, 0);               \
+               (cp)->page = NULL;                                      \
+       }                                                               \
+       if ((cp)->lock != LOCK_INVALID) {                               \
+               (void)__BT_TLPUT((dbp), (cp)->lock);                    \
+               (cp)->lock = LOCK_INVALID;                              \
+       }                                                               \
 }
 
 /*
@@ -85,9 +89,9 @@ __bam_cursor(dbp, txn, dbcp)
         * All cursors are queued from the master DB structure.  Add the
         * cursor to that queue.
         */
-       DB_THREAD_LOCK(dbp);
+       CURSOR_SETUP(dbp);
        TAILQ_INSERT_HEAD(&dbp->curs_queue, dbc, links);
-       DB_THREAD_UNLOCK(dbp);
+       CURSOR_TEARDOWN(dbp);
 
        *dbcp = dbc;
        return (0);
@@ -128,13 +132,6 @@ __bam_c_iclose(dbp, dbc)
        CURSOR *cp;
        int ret;
 
-       /*
-        * All cursors are queued from the master DB structure.  For
-        * now, discard the DB handle which triggered this call, and
-        * replace it with the cursor's reference.
-        */
-       dbp = dbc->dbp;
-
        /* If a cursor key was deleted, perform the actual deletion.  */
        cp = dbc->internal;
        ret = F_ISSET(cp, C_DELETED) ? __bam_c_physdel(dbp, cp, NULL) : 0;
@@ -144,9 +141,9 @@ __bam_c_iclose(dbp, dbc)
                (void)__BT_TLPUT(dbp, cp->lock);
 
        /* Remove the cursor from the queue. */
-       DB_THREAD_LOCK(dbp);
+       CURSOR_SETUP(dbp);
        TAILQ_REMOVE(&dbp->curs_queue, dbc, links);
-       DB_THREAD_UNLOCK(dbp);
+       CURSOR_TEARDOWN(dbp);
 
        /* Discard the structures. */
        FREE(dbc->internal, sizeof(CURSOR));
@@ -162,8 +159,9 @@ __bam_c_iclose(dbp, dbc)
 static int
 __bam_c_del(dbc, flags)
        DBC *dbc;
-       int flags;
+       u_int32_t flags;
 {
+       BTREE *t;
        CURSOR *cp;
        DB *dbp;
        DB_LOCK lock;
@@ -175,6 +173,7 @@ __bam_c_del(dbc, flags)
        DEBUG_LWRITE(dbc->dbp, dbc->txn, "bam_c_del", NULL, NULL, flags);
 
        cp = dbc->internal;
+       h = NULL;
 
        /* Check for invalid flags. */
        if ((ret = __db_cdelchk(dbc->dbp, flags,
@@ -186,6 +185,7 @@ __bam_c_del(dbc, flags)
                return (DB_KEYEMPTY);
 
        GETHANDLE(dbc->dbp, dbc->txn, &dbp, ret);
+       t = dbp->internal;
 
        /*
         * We don't physically delete the record until the cursor moves,
@@ -235,8 +235,21 @@ __bam_c_del(dbc, flags)
        (void)__bam_ca_delete(dbp, pgno, indx, NULL, 0);
 
        ret = memp_fput(dbp->mpf, h, DB_MPOOL_DIRTY);
+       h = NULL;
+
+       /*
+        * If it's a btree with record numbers, we have to adjust the
+        * counts.
+        */
+       if (F_ISSET(dbp, DB_BT_RECNUM) &&
+           (ret = __bam_c_getstack(dbp, cp)) == 0) {
+               ret = __bam_adjust(dbp, t, -1);
+               (void)__bam_stkrel(dbp);
+       }
 
-err:   PUTHANDLE(dbp);
+err:   if (h != NULL)
+               (void)memp_fput(dbp->mpf, h, 0);
+       PUTHANDLE(dbp);
        return (ret);
 }
 
@@ -244,14 +257,14 @@ err:      PUTHANDLE(dbp);
  * __bam_get --
  *     Retrieve a key/data pair from the tree.
  *
- * PUBLIC: int __bam_get __P((DB *, DB_TXN *, DBT *, DBT *, int));
+ * PUBLIC: int __bam_get __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t));
  */
 int
 __bam_get(argdbp, txn, key, data, flags)
        DB *argdbp;
        DB_TXN *txn;
        DBT *key, *data;
-       int flags;
+       u_int32_t flags;
 {
        DBC dbc;
        CURSOR cp;
@@ -289,7 +302,7 @@ static int
 __bam_c_get(dbc, key, data, flags)
        DBC *dbc;
        DBT *key, *data;
-       int flags;
+       u_int32_t flags;
 {
        BTREE *t;
        CURSOR *cp, copy;
@@ -448,7 +461,7 @@ __bam_c_rget(dbp, cp, data, flags)
        DB *dbp;
        CURSOR *cp;
        DBT *data;
-       int flags;
+       u_int32_t flags;
 {
        BTREE *t;
        DBT dbt;
@@ -491,7 +504,7 @@ static int
 __bam_c_put(dbc, key, data, flags)
        DBC *dbc;
        DBT *key, *data;
-       int flags;
+       u_int32_t flags;
 {
        BTREE *t;
        CURSOR *cp, copy;
@@ -499,7 +512,8 @@ __bam_c_put(dbc, key, data, flags)
        DBT dbt;
        db_indx_t indx;
        db_pgno_t pgno;
-       int exact, needkey, ret;
+       u_int32_t iiflags;
+       int exact, needkey, ret, stack;
        void *arg;
 
        DEBUG_LWRITE(dbc->dbp, dbc->txn, "bam_c_put",
@@ -524,29 +538,34 @@ __bam_c_put(dbc, key, data, flags)
         * To split, we need a valid key for the page.  Since it's a cursor,
         * we have to build one.
         */
+       stack = 0;
        if (0) {
-split:         if (needkey) {
+split:         /* Acquire a copy of a key from the page. */
+               if (needkey) {
                        memset(&dbt, 0, sizeof(DBT));
-                       ret = __db_ret(dbp, cp->page, indx,
-                           &dbt, &t->bt_rkey.data, &t->bt_rkey.ulen);
-
-                       DISCARD(dbp, cp);
-
-                       if (ret)
+                       if ((ret = __db_ret(dbp, cp->page, indx,
+                           &dbt, &t->bt_rkey.data, &t->bt_rkey.ulen)) != 0)
                                goto err;
                        arg = &dbt;
-               } else {
-                       (void)__bam_stkrel(dbp);
+               } else
                        arg = key;
-               }
+
+               /* Discard any pinned pages. */
+               if (stack) {
+                       (void)__bam_stkrel(dbp);
+                       stack = 0;
+               } else
+                       DISCARD(dbp, cp);
+
                if ((ret = __bam_split(dbp, arg)) != 0)
                        goto err;
        }
 
-       /* If there's no key supplied, use the cursor. */
-       if (flags == DB_KEYFIRST || flags == DB_KEYLAST)
-               needkey = 0;
-       else {
+       ret = 0;
+       switch (flags) {
+       case DB_AFTER:
+       case DB_BEFORE:
+       case DB_CURRENT:
                needkey = 1;
                if (cp->dpgno == PGNO_INVALID) {
                        pgno = cp->pgno;
@@ -555,41 +574,53 @@ split:            if (needkey) {
                        pgno = cp->dpgno;
                        indx = cp->dindx;
                }
-               /* Acquire the current page. */
-               if ((ret = __bam_lget(dbp,
-                   0, cp->pgno, DB_LOCK_WRITE, &cp->lock)) != 0)
-                       goto err;
-               if ((ret = __bam_pget(dbp, &cp->page, &pgno, 0)) != 0)
-                       goto err;
-       }
+               /*
+                * XXX
+                * This test is right -- we don't currently support duplicates
+                * in the presence of record numbers, so we don't worry about
+                * them if DB_BT_RECNUM is set.
+                */
+               if (F_ISSET(dbp, DB_BT_RECNUM) &&
+                   (flags != DB_CURRENT || F_ISSET(cp, C_DELETED))) {
+                       /* Acquire a complete stack. */
+                       if ((ret = __bam_c_getstack(dbp, cp)) != 0)
+                               goto err;
+                       cp->page = t->bt_csp->page;
 
-       ret = 0;
-       switch (flags) {
-       case DB_AFTER:
-       case DB_BEFORE:
-       case DB_CURRENT:
+                       stack = 1;
+                       iiflags = BI_DOINCR;
+               } else {
+                       /* Acquire the current page. */
+                       if ((ret = __bam_lget(dbp,
+                           0, cp->pgno, DB_LOCK_WRITE, &cp->lock)) == 0)
+                               ret = __bam_pget(dbp, &cp->page, &pgno, 0);
+                       if (ret != 0)
+                               goto err;
+
+                       iiflags = 0;
+               }
                if ((ret = __bam_iitem(dbp, &cp->page,
-                   &indx, key, data, flags, 0)) == DB_NEEDSPLIT)
+                   &indx, key, data, flags, iiflags)) == DB_NEEDSPLIT)
                        goto split;
                break;
        case DB_KEYFIRST:
-               exact = 0;
+               exact = needkey = 0;
                if ((ret =
                    __bam_c_search(dbp, cp, key, S_KEYFIRST, 0, &exact)) != 0)
                        goto err;
+               stack = 1;
 
                indx = cp->dpgno == PGNO_INVALID ? cp->indx : cp->dindx;
                if ((ret = __bam_iitem(dbp, &cp->page, &indx, key,
                    data, DB_BEFORE, exact ? 0 : BI_NEWKEY)) == DB_NEEDSPLIT)
                        goto split;
-               if (ret)
-                       goto err;
                break;
        case DB_KEYLAST:
-               exact = 0;
+               exact = needkey = 0;
                if ((ret =
                    __bam_c_search(dbp, cp, key, S_KEYLAST, 0, &exact)) != 0)
                        goto err;
+               stack = 1;
 
                indx = cp->dpgno == PGNO_INVALID ? cp->indx : cp->dindx;
                if ((ret = __bam_iitem(dbp, &cp->page, &indx, key,
@@ -623,13 +654,27 @@ split:            if (needkey) {
        if (copy.lock != LOCK_INVALID)
                (void)__BT_TLPUT(dbp, copy.lock);
 
-       /* Discard the pinned page. */
-       ret = memp_fput(dbp->mpf, cp->page, 0);
+       /*
+        * Discard any pages pinned in the tree and their locks, except for
+        * the leaf page, for which we only discard the pin, not the lock.
+        *
+        * Note, the leaf page participated in the stack we acquired, and so
+        * we have to adjust the stack as necessary.  If there was only a
+        * single page on the stack, we don't have to free further stack pages.
+        */
+
+       if (stack && BT_STK_POP(t) != NULL)
+               (void)__bam_stkrel(dbp);
+
+       if ((ret = memp_fput(dbp->mpf, cp->page, 0)) != 0)
+               goto err;
+
        if (0) {
-err:           if (cp->page != NULL)
-                       (void)memp_fput(dbp->mpf, cp->page, 0);
-               if (cp->lock != LOCK_INVALID)
-                       (void)__BT_TLPUT(dbp, cp->lock);
+err:           /* Discard any pinned pages. */
+               if (stack)
+                       (void)__bam_stkrel(dbp);
+               else
+                       DISCARD(dbp, cp);
                *cp = copy;
        }
 
@@ -976,7 +1021,7 @@ __bam_c_search(dbp, cp, key, flags, isrecno, exactp)
        DB *dbp;
        CURSOR *cp;
        const DBT *key;
-       u_int flags;
+       u_int32_t flags;
        int isrecno, *exactp;
 {
        BTREE *t;
@@ -1032,6 +1077,18 @@ __bam_c_search(dbp, cp, key, flags, isrecno, exactp)
                } else
                        if ((ret = __bam_c_next(dbp, cp, 0)) != 0)
                                return (ret);
+       /*
+        * If we don't specify an exact match (the DB_KEYFIRST/DB_KEYLAST or
+        * DB_SET_RANGE flags were set) __bam_search() may return a deleted
+        * item.  For DB_KEYFIRST/DB_KEYLAST, we don't care since we're only
+        * using it for a tree position.  For DB_SET_RANGE, we're returning
+        * the key, so we have to adjust it.
+        */
+       if (LF_ISSET(S_DELNO) && cp->dpgno == PGNO_INVALID &&
+           B_DISSET(GET_BKEYDATA(cp->page, cp->indx + O_INDX)->type))
+               if ((ret = __bam_c_next(dbp, cp, 0)) != 0)
+                       return (ret);
+
        return (0);
 }
 
@@ -1101,7 +1158,7 @@ __bam_cprint(dbp)
        CURSOR *cp;
        DBC *dbc;
 
-       DB_THREAD_LOCK(dbp);
+       CURSOR_SETUP(dbp);
        for (dbc = TAILQ_FIRST(&dbp->curs_queue);
            dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
                cp = (CURSOR *)dbc->internal;
@@ -1113,7 +1170,8 @@ __bam_cprint(dbp)
                        fprintf(stderr, "(deleted)");
                fprintf(stderr, "\n");
        }
-       DB_THREAD_UNLOCK(dbp);
+       CURSOR_TEARDOWN(dbp);
+
        return (0);
 }
 #endif /* DEBUG */
@@ -1135,7 +1193,7 @@ __bam_ca_delete(dbp, pgno, indx, curs, key_delete)
 {
        DBC *dbc;
        CURSOR *cp;
-       int count;
+       int count;              /* !!!: Has to contain max number of cursors. */
 
        /*
         * Adjust the cursors.  We don't have to review the cursors for any
@@ -1148,8 +1206,7 @@ __bam_ca_delete(dbp, pgno, indx, curs, key_delete)
         * locks on the same page, but, cursors within a thread must be single
         * threaded, so all we're locking here is the cursor linked list.
         */
-       DB_THREAD_LOCK(dbp);
-
+       CURSOR_SETUP(dbp);
        for (count = 0, dbc = TAILQ_FIRST(&dbp->curs_queue);
            dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
                cp = (CURSOR *)dbc->internal;
@@ -1180,8 +1237,8 @@ __bam_ca_delete(dbp, pgno, indx, curs, key_delete)
                                F_SET(cp, C_DELETED);
                        }
        }
+       CURSOR_TEARDOWN(dbp);
 
-       DB_THREAD_UNLOCK(dbp);
        return (count);
 }
 
@@ -1192,11 +1249,11 @@ __bam_ca_delete(dbp, pgno, indx, curs, key_delete)
  * PUBLIC: void __bam_ca_di __P((DB *, db_pgno_t, u_int32_t, int));
  */
 void
-__bam_ca_di(dbp, pgno, indx, value)
+__bam_ca_di(dbp, pgno, indx, adjust)
        DB *dbp;
        db_pgno_t pgno;
        u_int32_t indx;
-       int value;
+       int adjust;
 {
        CURSOR *cp;
        DBC *dbc;
@@ -1208,16 +1265,16 @@ __bam_ca_di(dbp, pgno, indx, value)
        /*
         * Adjust the cursors.  See the comment in __bam_ca_delete().
         */
-       DB_THREAD_LOCK(dbp);
+       CURSOR_SETUP(dbp);
        for (dbc = TAILQ_FIRST(&dbp->curs_queue);
            dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
                cp = (CURSOR *)dbc->internal;
                if (cp->pgno == pgno && cp->indx >= indx)
-                       cp->indx += value;
+                       cp->indx += adjust;
                if (cp->dpgno == pgno && cp->dindx >= indx)
-                       cp->dindx += value;
+                       cp->dindx += adjust;
        }
-       DB_THREAD_UNLOCK(dbp);
+       CURSOR_TEARDOWN(dbp);
 }
 
 /*
@@ -1242,7 +1299,7 @@ __bam_ca_dup(dbp, fpgno, first, fi, tpgno, ti)
         * No need to test duplicates, this only gets called when moving
         * leaf page data items onto a duplicates page.
         */
-       DB_THREAD_LOCK(dbp);
+       CURSOR_SETUP(dbp);
        for (dbc = TAILQ_FIRST(&dbp->curs_queue);
            dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
                cp = (CURSOR *)dbc->internal;
@@ -1258,7 +1315,7 @@ __bam_ca_dup(dbp, fpgno, first, fi, tpgno, ti)
                        cp->dindx = ti;
                }
        }
-       DB_THREAD_UNLOCK(dbp);
+       CURSOR_TEARDOWN(dbp);
 }
 
 /*
@@ -1285,14 +1342,14 @@ __bam_ca_move(dbp, fpgno, tpgno)
         * No need to test duplicates, this only gets called when copying
         * over the root page with a leaf or internal page.
         */
-       DB_THREAD_LOCK(dbp);
+       CURSOR_SETUP(dbp);
        for (dbc = TAILQ_FIRST(&dbp->curs_queue);
            dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
                cp = (CURSOR *)dbc->internal;
                if (cp->pgno == fpgno)
                        cp->pgno = tpgno;
        }
-       DB_THREAD_UNLOCK(dbp);
+       CURSOR_TEARDOWN(dbp);
 }
 
 /*
@@ -1333,7 +1390,7 @@ __bam_ca_replace(dbp, pgno, indx, pass)
         * for the cursor as it may have been changed by other cursor update
         * routines as the item was deleted/inserted.
         */
-       DB_THREAD_LOCK(dbp);
+       CURSOR_SETUP(dbp);
        switch (pass) {
        case REPLACE_SETUP:                     /* Setup. */
                for (dbc = TAILQ_FIRST(&dbp->curs_queue);
@@ -1372,7 +1429,7 @@ __bam_ca_replace(dbp, pgno, indx, pass)
                }
                break;
        }
-       DB_THREAD_UNLOCK(dbp);
+       CURSOR_TEARDOWN(dbp);
 }
 
 /*
@@ -1406,7 +1463,7 @@ __bam_ca_split(dbp, ppgno, lpgno, rpgno, split_indx, cleft)
         * the cursor is on the right page, it is decremented by the number of
         * records split to the left page.
         */
-       DB_THREAD_LOCK(dbp);
+       CURSOR_SETUP(dbp);
        for (dbc = TAILQ_FIRST(&dbp->curs_queue);
            dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
                cp = (CURSOR *)dbc->internal;
@@ -1427,7 +1484,7 @@ __bam_ca_split(dbp, ppgno, lpgno, rpgno, split_indx, cleft)
                                cp->dindx -= split_indx;
                        }
        }
-       DB_THREAD_UNLOCK(dbp);
+       CURSOR_TEARDOWN(dbp);
 }
 
 /*
@@ -1440,16 +1497,17 @@ __bam_c_physdel(dbp, cp, h)
        CURSOR *cp;
        PAGE *h;
 {
+       enum { DELETE_ITEM, DELETE_PAGE, NOTHING_FURTHER } cmd;
        BOVERFLOW bo;
        BTREE *t;
        DBT dbt;
        DB_LOCK lock;
        db_indx_t indx;
        db_pgno_t pgno, next_pgno, prev_pgno;
-       int local, normal, ret;
+       int delete_page, local_page, ret;
 
        t = dbp->internal;
-       ret = 0;
+       delete_page = ret = 0;
 
        /* Figure out what we're deleting. */
        if (cp->dpgno == PGNO_INVALID) {
@@ -1476,9 +1534,9 @@ __bam_c_physdel(dbp, cp, h)
                        return (ret);
                if ((ret = __bam_pget(dbp, &h, &pgno, 0)) != 0)
                        return (ret);
-               local = 1;
+               local_page = 1;
        } else
-               local = 0;
+               local_page = 0;
 
        /*
         * If we're deleting a duplicate entry and there are other duplicate
@@ -1515,9 +1573,9 @@ __bam_c_physdel(dbp, cp, h)
 
                if (NUM_ENT(h) == 1 &&
                    prev_pgno == PGNO_INVALID && next_pgno == PGNO_INVALID)
-                       normal = 1;
+                       cmd = DELETE_PAGE;
                else {
-                       normal = 0;
+                       cmd = DELETE_ITEM;
 
                        /* Delete the duplicate. */
                        if ((ret = __db_drem(dbp, &h, indx, __bam_free)) != 0)
@@ -1536,18 +1594,27 @@ __bam_c_physdel(dbp, cp, h)
                         */
                        if ((h != NULL && pgno == h->pgno) ||
                            prev_pgno != PGNO_INVALID)
-                               goto done;
+                               cmd = NOTHING_FURTHER;
                }
 
-               /* Release any page we're holding and its lock. */
-               if (local) {
+               /*
+                * Release any page we're holding and its lock.
+                *
+                * !!!
+                * If there is no subsequent page in the duplicate chain, then
+                * __db_drem will have put page "h" and set it to NULL.
+               */
+               if (local_page) {
                        if (h != NULL)
                                (void)memp_fput(dbp->mpf, h, 0);
                        (void)__BT_TLPUT(dbp, lock);
-                       local = 0;
+                       local_page = 0;
                }
 
-               /* Acquire the parent page. */
+               if (cmd == NOTHING_FURTHER)
+                       goto done;
+
+               /* Acquire the parent page and switch the index to its entry. */
                if ((ret =
                    __bam_lget(dbp, 0, cp->pgno, DB_LOCK_WRITE, &lock)) != 0)
                        goto err;
@@ -1555,11 +1622,10 @@ __bam_c_physdel(dbp, cp, h)
                        (void)__BT_TLPUT(dbp, lock);
                        goto err;
                }
-               local = 1;
-
-               /* Switch to the parent page's entry. */
+               local_page = 1;
                indx = cp->indx;
-               if (normal)
+
+               if (cmd == DELETE_PAGE)
                        goto btd;
 
                /*
@@ -1582,47 +1648,60 @@ __bam_c_physdel(dbp, cp, h)
                goto done;
        }
 
-       /* Otherwise, do a normal btree delete. */
-btd:   if ((ret = __bam_ditem(dbp, h, indx)) != 0)
-               goto err;
-       if ((ret = __bam_ditem(dbp, h, indx)) != 0)
-               goto err;
-
-       /*
-        * If the page is empty, delete it.  To delete a leaf page we need a
-        * copy of a key from the page.  We use the first one that was there,
-        * since it's the last key that the page held.  We malloc the page
-        * information instead of using the return key/data memory because
-        * we've already set them -- the reason that we've already set them
-        * is because we're (potentially) about to do a reverse split, which
-        * would make our saved page information useless.
+btd:   /*
+        * If the page is going to be emptied, delete it.  To delete a leaf
+        * page we need a copy of a key from the page.  We use the 0th page
+        * index since it's the last key that the page held.
+        *
+        * We malloc the page information instead of using the return key/data
+        * memory because we've already set them -- the reason we've already
+        * set them is because we're (potentially) about to do a reverse split,
+        * which would make our saved page information useless.
         *
         * XXX
         * The following operations to delete a page might deadlock.  I think
         * that's OK.  The problem is if we're deleting an item because we're
         * closing cursors because we've already deadlocked and want to call
-        * txn_abort().  If we fail due to deadlock, we'll leave an locked
-        * empty page in the tree, which won't be empty long because we're
-        * going to undo the delete.
+        * txn_abort().  If we fail due to deadlock, we leave a locked empty
+        * page in the tree, which won't be empty long because we're going to
+        * undo the delete.
         */
-       if (NUM_ENT(h) == 0 && h->pgno != PGNO_ROOT) {
+       if (NUM_ENT(h) == 2 && h->pgno != PGNO_ROOT) {
                memset(&dbt, 0, sizeof(DBT));
                dbt.flags = DB_DBT_MALLOC | DB_DBT_INTERNAL;
                if ((ret = __db_ret(dbp, h, 0, &dbt, NULL, NULL)) != 0)
                        goto err;
+               delete_page = 1;
+       }
 
-               if (local) {
-                       (void)memp_fput(dbp->mpf, h, 0);
-                       (void)__BT_TLPUT(dbp, lock);
-                       local = 0;
-               }
+       /*
+        * Do a normal btree delete.
+        *
+        * XXX
+        * Delete the key item first, otherwise the duplicate checks in
+        * __bam_ditem() won't work!
+        */
+       if ((ret = __bam_ditem(dbp, h, indx)) != 0)
+               goto err;
+       if ((ret = __bam_ditem(dbp, h, indx)) != 0)
+               goto err;
 
-               ret = __bam_dpage(dbp, &dbt);
-               __db_free(dbt.data);
+       /* Discard any remaining locks/pages. */
+       if (local_page) {
+               (void)memp_fput(dbp->mpf, h, 0);
+               (void)__BT_TLPUT(dbp, lock);
+               local_page = 0;
        }
 
+       /* Delete the page if it was emptied. */
+       if (delete_page)
+               ret = __bam_dpage(dbp, &dbt);
+
 err:
-done:  if (local) {
+done:  if (delete_page)
+               __db_free(dbt.data);
+
+       if (local_page) {
                (void)memp_fput(dbp->mpf, h, 0);
                (void)__BT_TLPUT(dbp, lock);
        }
@@ -1631,3 +1710,43 @@ done:    if (local) {
                ++t->lstat.bt_deleted;
        return (ret);
 }
+
+/*
+ * __bam_c_getstack --
+ *     Acquire a full stack for a cursor.
+ */
+static int
+__bam_c_getstack(dbp, cp)
+       DB *dbp;
+       CURSOR *cp;
+{
+       DBT dbt;
+       PAGE *h;
+       db_pgno_t pgno;
+       int exact, ret;
+
+       ret = 0;
+       h = NULL;
+       memset(&dbt, 0, sizeof(DBT));
+
+       /* Get the page with the current item on it. */
+       pgno = cp->pgno;
+       if ((ret = __bam_pget(dbp, &h, &pgno, 0)) != 0)
+               return (ret);
+
+       /* Get a copy of a key from the page. */
+       dbt.flags = DB_DBT_MALLOC | DB_DBT_INTERNAL;
+       if ((ret = __db_ret(dbp, h, 0, &dbt, NULL, NULL)) != 0)
+               goto err;
+
+       /* Get a write-locked stack for that page. */
+       exact = 0;
+       ret = __bam_search(dbp, &dbt, S_KEYFIRST, 1, NULL, &exact);
+
+       /* We no longer need the key or the page. */
+err:   if (h != NULL)
+               (void)memp_fput(dbp->mpf, h, 0);
+       if (dbt.data != NULL)
+               __db_free(dbt.data);
+       return (ret);
+}
index baa8a25..7e71037 100644 (file)
@@ -1,7 +1,7 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 1996, 1997
+ * Copyright (c) 1996, 1997, 1998
  *     Sleepycat Software.  All rights reserved.
  */
 /*
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)bt_delete.c  10.25 (Sleepycat) 1/8/98";
+static const char sccsid[] = "@(#)bt_delete.c  10.31 (Sleepycat) 5/6/98";
 #endif /* not lint */
 
 #ifndef NO_SYSTEM_INCLUDES
 #include <sys/types.h>
 
-#include <stdio.h>
 #include <string.h>
 #endif
 
@@ -67,14 +66,14 @@ static int __bam_dpages __P((DB *, BTREE *));
  * __bam_delete --
  *     Delete the items referenced by a key.
  *
- * PUBLIC: int __bam_delete __P((DB *, DB_TXN *, DBT *, int));
+ * PUBLIC: int __bam_delete __P((DB *, DB_TXN *, DBT *, u_int32_t));
  */
 int
 __bam_delete(argdbp, txn, key, flags)
        DB *argdbp;
        DB_TXN *txn;
        DBT *key;
-       int flags;
+       u_int32_t flags;
 {
        BTREE *t;
        DB *dbp;
@@ -87,8 +86,8 @@ __bam_delete(argdbp, txn, key, flags)
        stack = 0;
 
        /* Check for invalid flags. */
-       if ((ret =
-           __db_delchk(argdbp, flags, F_ISSET(argdbp, DB_AM_RDONLY))) != 0)
+       if ((ret = __db_delchk(argdbp,
+           key, flags, F_ISSET(argdbp, DB_AM_RDONLY))) != 0)
                return (ret);
 
        GETHANDLE(argdbp, txn, &dbp, ret);
@@ -107,6 +106,11 @@ __bam_delete(argdbp, txn, key, flags)
                        break;
        for (; cnt > 0; --cnt, ++t->lstat.bt_deleted)
                if (__bam_ca_delete(dbp, h->pgno, indx, NULL, 1) == 0) {
+                       /*
+                        * XXX
+                        * Delete the key item first, otherwise the duplicate
+                        * checks in __bam_ditem() won't work!
+                        */
                        if ((ret = __bam_ditem(dbp, h, indx)) != 0)
                                goto err;
                        if ((ret = __bam_ditem(dbp, h, indx)) != 0)
@@ -138,14 +142,14 @@ err:      if (stack)
  * __ram_delete --
  *     Delete the items referenced by a key.
  *
- * PUBLIC: int __ram_delete __P((DB *, DB_TXN *, DBT *, int));
+ * PUBLIC: int __ram_delete __P((DB *, DB_TXN *, DBT *, u_int32_t));
  */
 int
 __ram_delete(argdbp, txn, key, flags)
        DB *argdbp;
        DB_TXN *txn;
        DBT *key;
-       int flags;
+       u_int32_t flags;
 {
        BKEYDATA bk;
        BTREE *t;
@@ -159,8 +163,8 @@ __ram_delete(argdbp, txn, key, flags)
        stack = 0;
 
        /* Check for invalid flags. */
-       if ((ret =
-           __db_delchk(argdbp, flags, F_ISSET(argdbp, DB_AM_RDONLY))) != 0)
+       if ((ret = __db_delchk(argdbp,
+           key, flags, F_ISSET(argdbp, DB_AM_RDONLY))) != 0)
                return (ret);
 
        GETHANDLE(argdbp, txn, &dbp, ret);
@@ -284,19 +288,32 @@ __bam_ditem(dbp, h, indx)
        case P_LBTREE:
                /*
                 * If it's a duplicate key, discard the index and don't touch
-                * the actual page item.  This works because no data item can
-                * have an index that matches any other index so even if the
-                * data item is in an index "slot", it won't match any other
-                * index.
+                * the actual page item.
+                *
+                * XXX
+                * This works because no data item can have an index matching
+                * any other index so even if the data item is in a key "slot",
+                * it won't match any other index.
                 */
-               if (!(indx % 2)) {
-                       if (indx > 0 && h->inp[indx] == h->inp[indx - P_INDX])
-                               return (__bam_adjindx(dbp,
-                                   h, indx, indx - P_INDX, 0));
+               if ((indx % 2) == 0) {
+                       /*
+                        * Check for a duplicate after us on the page.  NOTE:
+                        * we have to delete the key item before deleting the
+                        * data item, otherwise the "indx + P_INDX" calculation
+                        * won't work!
+                        */
                        if (indx + P_INDX < (u_int32_t)NUM_ENT(h) &&
                            h->inp[indx] == h->inp[indx + P_INDX])
                                return (__bam_adjindx(dbp,
                                    h, indx, indx + O_INDX, 0));
+                       /*
+                        * Check for a duplicate before us on the page.  It
+                        * doesn't matter if we delete the key item before or
+                        * after the data item for the purposes of this one.
+                        */
+                       if (indx > 0 && h->inp[indx] == h->inp[indx - P_INDX])
+                               return (__bam_adjindx(dbp,
+                                   h, indx, indx - P_INDX, 0));
                }
                /* FALLTHROUGH */
        case P_LRECNO:
@@ -396,7 +413,8 @@ __bam_dpage(dbp, key)
        DB_LOCK lock;
        PAGE *h;
        db_pgno_t pgno;
-       int exact, level, ret;
+       int level;              /* !!!: has to hold number of tree levels. */
+       int exact, ret;
 
        ret = 0;
        t = dbp->internal;
@@ -527,13 +545,14 @@ __bam_dpages(dbp, t)
                goto release;
 
        /*
-        * If we deleted the next-to-last item from the root page, the tree
-        * can collapse a level.  Try and write lock the remaining root + 1
-        * page and copy it onto the root page.  If we can't get the lock,
-        * that's okay, the tree just stays a level deeper than we'd like.
+        * If we just deleted the last or next-to-last item from the root page,
+        * the tree can collapse a level.  Write lock the last page referenced
+        * by the root page and copy it over the root page.  If we can't get a
+        * write lock, that's okay, the tree just remains a level deeper than
+        * we'd like.
         */
        h = epg->page;
-       if (h->pgno == PGNO_ROOT && NUM_ENT(h) == 1) {
+       if (h->pgno == PGNO_ROOT && NUM_ENT(h) <= 1) {
                pgno = TYPE(epg->page) == P_IBTREE ?
                    GET_BINTERNAL(epg->page, 0)->pgno :
                    GET_RINTERNAL(epg->page, 0)->pgno;
@@ -573,13 +592,21 @@ __bam_dpages(dbp, t)
                (void)memp_fset(dbp->mpf, epg->page, DB_MPOOL_DIRTY);
 
                /*
-                * Free the last page in that level of the btree and discard
-                * the lock.  (The call to __bam_free discards our reference
+                * Free the page copied onto the root page and discard its
+                * lock.  (The call to __bam_free() discards our reference
                 * to the page.)
+                *
+                * It's possible that the reverse split we're doing involves
+                * pages from the stack of pages we're deleting.  Don't free
+                * the page twice.
                 */
-               (void)__bam_free(dbp, h);
+                if (h->pgno == (epg + 1)->page->pgno)
+                       (void)memp_fput(dbp->mpf, h, 0);
+               else {
+                       (void)__bam_free(dbp, h);
+                       ++t->lstat.bt_freed;
+               }
                (void)__BT_TLPUT(dbp, lock);
-               ++t->lstat.bt_freed;
 
                /* Adjust the cursors. */
                __bam_ca_move(dbp, h->pgno, PGNO_ROOT);
@@ -596,12 +623,17 @@ __bam_dpages(dbp, t)
         * Don't bother checking for errors.  We've unlinked the subtree from
         * the tree, and there's no possibility of recovery.
         */
-       for (; ++epg <= t->bt_csp; ++t->lstat.bt_freed) {
+       while (++epg <= t->bt_csp) {
+               /*
+                * XXX
+                * Why do we need to do this?  Isn't the page already empty?
+                */
                if (NUM_ENT(epg->page) != 0)
                        (void)__bam_ditem(dbp, epg->page, epg->indx);
 
                (void)__bam_free(dbp, epg->page);
                (void)__BT_TLPUT(dbp, epg->lock);
+               ++t->lstat.bt_freed;
        }
        return (0);
 
index dd9f109..f5974ec 100644 (file)
@@ -1,7 +1,7 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 1996, 1997
+ * Copyright (c) 1996, 1997, 1998
  *     Sleepycat Software.  All rights reserved.
  */
 /*
@@ -47,7 +47,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)bt_open.c    10.22 (Sleepycat) 1/6/98";
+static const char sccsid[] = "@(#)bt_open.c    10.27 (Sleepycat) 5/6/98";
 #endif /* not lint */
 
 /*
@@ -60,21 +60,15 @@ static const char sccsid[] = "@(#)bt_open.c 10.22 (Sleepycat) 1/6/98";
 
 #ifndef NO_SYSTEM_INCLUDES
 #include <sys/types.h>
-#include <sys/stat.h>
 
 #include <errno.h>
-#include <fcntl.h>
 #include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
 #include <string.h>
-#include <unistd.h>
 #endif
 
 #include "db_int.h"
 #include "db_page.h"
 #include "btree.h"
-#include "common_ext.h"
 
 static int __bam_keyalloc __P((BTREE *));
 static int __bam_setmeta __P((DB *, BTREE *));
@@ -295,6 +289,7 @@ __bam_setmeta(dbp, t)
        }
 
        /* Initialize the tree structure metadata information. */
+       memset(meta, 0, sizeof(BTMETA));
        ZERO_LSN(meta->lsn);
        meta->pgno = PGNO_METADATA;
        meta->magic = DB_BTREEMAGIC;
@@ -303,7 +298,6 @@ __bam_setmeta(dbp, t)
        meta->maxkey = t->bt_maxkey;
        meta->minkey = t->bt_minkey;
        meta->free = PGNO_INVALID;
-       meta->flags = 0;
        if (dbp->type == DB_RECNO)
                F_SET(meta, BTM_RECNO);
        if (F_ISSET(dbp, DB_AM_DUP))
@@ -314,8 +308,6 @@ __bam_setmeta(dbp, t)
                F_SET(meta, BTM_RECNUM);
        if (F_ISSET(dbp, DB_RE_RENUMBER))
                F_SET(meta, BTM_RENUMBER);
-       meta->re_len = 0;
-       meta->re_pad = 0;
        memcpy(meta->uid, dbp->lock.fileid, DB_FILE_ID_LEN);
 
        /* Create and initialize a root page. */
index 853317e..87f2811 100644 (file)
@@ -1,7 +1,7 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 1996, 1997
+ * Copyright (c) 1996, 1997, 1998
  *     Sleepycat Software.  All rights reserved.
  */
 /*
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)bt_page.c    10.7 (Sleepycat) 1/7/98";
+static const char sccsid[] = "@(#)bt_page.c    10.12 (Sleepycat) 5/6/98";
 #endif /* not lint */
 
 #ifndef NO_SYSTEM_INCLUDES
 #include <sys/types.h>
 
 #include <errno.h>
-#include <stdio.h>
 #include <string.h>
 #endif
 
@@ -142,7 +141,8 @@ __bam_free(dbp, h)
        DBT ldbt;
        DB_LOCK metalock;
        db_pgno_t pgno;
-       int is_dirty, ret, t_ret;
+       u_int32_t dirty_flag;
+       int ret, t_ret;
 
        /*
         * Retrieve the metadata page and insert the page at the head of
@@ -150,7 +150,7 @@ __bam_free(dbp, h)
         * fail, then we need to put the page with which we were called
         * back because our caller assumes we take care of it.
         */
-       is_dirty = 0;
+       dirty_flag = 0;
        pgno = PGNO_METADATA;
        if ((ret = __bam_lget(dbp, 0, pgno, DB_LOCK_WRITE, &metalock)) != 0)
                goto err;
@@ -178,7 +178,7 @@ __bam_free(dbp, h)
         * The page should have nothing interesting on it, re-initialize it,
         * leaving only the page number and the LSN.
         */
-#ifdef DEBUG
+#ifdef DIAGNOSTIC
        { db_pgno_t __pgno; DB_LSN __lsn;
                __pgno = h->pgno;
                __lsn = h->lsn;
@@ -198,8 +198,8 @@ __bam_free(dbp, h)
                ret = t_ret;
 
        /* Discard the caller's page reference. */
-       is_dirty = DB_MPOOL_DIRTY;
-err:   if ((t_ret = memp_fput(dbp->mpf, h, is_dirty)) != 0 && ret == 0)
+       dirty_flag = DB_MPOOL_DIRTY;
+err:   if ((t_ret = memp_fput(dbp->mpf, h, dirty_flag)) != 0 && ret == 0)
                ret = t_ret;
 
        /*
@@ -248,8 +248,10 @@ __bam_lget(dbp, do_couple, pgno, mode, lockp)
        u_int32_t locker;
        int ret;
 
-       if (!F_ISSET(dbp, DB_AM_LOCKING))
+       if (!F_ISSET(dbp, DB_AM_LOCKING)) {
+               *lockp = LOCK_INVALID;
                return (0);
+       }
 
        locker = dbp->txn == NULL ? dbp->locker : dbp->txn->txnid;
        dbp->lock.pgno = pgno;
@@ -300,15 +302,15 @@ __bam_lput(dbp, lock)
  * __bam_pget --
  *     The standard page get call.
  *
- * PUBLIC: int __bam_pget __P((DB *, PAGE **, db_pgno_t *, int));
+ * PUBLIC: int __bam_pget __P((DB *, PAGE **, db_pgno_t *, u_int32_t));
  */
 int
-__bam_pget(dbp, hp, pgnop, mflags)
+__bam_pget(dbp, hp, pgnop, mpool_flags)
        DB *dbp;
        PAGE **hp;
        db_pgno_t *pgnop;
-       int mflags;
+       u_int32_t mpool_flags;
 {
        return (memp_fget((dbp)->mpf,
-           pgnop, mflags, hp) == 0 ? 0 : __db_pgerr(dbp, *pgnop));
+           pgnop, mpool_flags, hp) == 0 ? 0 : __db_pgerr(dbp, *pgnop));
 }
index 87f3fd9..a93faac 100644 (file)
@@ -1,7 +1,7 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 1996, 1997
+ * Copyright (c) 1996, 1997, 1998
  *     Sleepycat Software.  All rights reserved.
  */
 /*
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)bt_put.c     10.38 (Sleepycat) 1/8/98";
+static const char sccsid[] = "@(#)bt_put.c     10.45 (Sleepycat) 5/25/98";
 #endif /* not lint */
 
 #ifndef NO_SYSTEM_INCLUDES
 #include <sys/types.h>
 
 #include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
 #include <string.h>
 #endif
 
@@ -75,21 +73,22 @@ static u_int32_t __bam_partsize __P((DBT *, PAGE *, u_int32_t));
  * __bam_put --
  *     Add a new key/data pair or replace an existing pair (btree).
  *
- * PUBLIC: int __bam_put __P((DB *, DB_TXN *, DBT *, DBT *, int));
+ * PUBLIC: int __bam_put __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t));
  */
 int
 __bam_put(argdbp, txn, key, data, flags)
        DB *argdbp;
        DB_TXN *txn;
        DBT *key, *data;
-       int flags;
+       u_int32_t flags;
 {
        BTREE *t;
        CURSOR c;
        DB *dbp;
        PAGE *h;
        db_indx_t indx;
-       int exact, iflags, isdeleted, newkey, replace, ret, stack;
+       u_int32_t iitem_flags, insert_flags;
+       int exact, isdeleted, newkey, ret, stack;
 
        DEBUG_LWRITE(argdbp, txn, "bam_put", key, data, flags);
 
@@ -121,14 +120,13 @@ retry:    /*
         * been marked for deletion, we do a replace, otherwise, it has to be
         * a set of duplicates, and we simply append a new one to the set.
         */
-       isdeleted = replace = 0;
+       isdeleted = 0;
        if (exact) {
                if ((ret = __bam_isdeleted(dbp, h, indx, &isdeleted)) != 0)
                        goto err;
-               if (isdeleted) {
-                       replace = 1;
+               if (isdeleted)
                        __bam_ca_replace(dbp, h->pgno, indx, REPLACE_SETUP);
-               else
+               else
                        if (flags == DB_NOOVERWRITE) {
                                ret = DB_KEYEXIST;
                                goto err;
@@ -179,42 +177,38 @@ retry:    /*
                                t->bt_csp->page = h = c.page;
                                indx = c.dindx;
                        }
-                       iflags = DB_AFTER;
+                       insert_flags = DB_AFTER;
                } else
-                       iflags = DB_CURRENT;
+                       insert_flags = DB_CURRENT;
        } else
-               iflags = DB_BEFORE;
+               insert_flags = DB_BEFORE;
 
        /*
         * The pages we're using may be modified by __bam_iitem(), so make
         * sure we reset the stack.
         */
-       ret = __bam_iitem(dbp,
-           &h, &indx, key, data, iflags, newkey ? BI_NEWKEY : 0);
+       iitem_flags = 0;
+       if (newkey)
+               iitem_flags |= BI_NEWKEY;
+       if (isdeleted)
+               iitem_flags |= BI_DOINCR;
+       ret = __bam_iitem(dbp, &h, &indx, key, data, insert_flags, iitem_flags);
        t->bt_csp->page = h;
        t->bt_csp->indx = indx;
 
        switch (ret) {
        case 0:
-               /*
-                * Done.  Clean up the cursor, and, if we're doing record
-                * numbers, adjust the internal page counts.
-                */
-               if (replace)
+               /* Done.  Clean up the cursor. */
+               if (isdeleted)
                        __bam_ca_replace(dbp, h->pgno, indx, REPLACE_SUCCESS);
-
-               if (!replace && F_ISSET(dbp, DB_BT_RECNUM))
-                       ret = __bam_adjust(dbp, t, 1);
                break;
        case DB_NEEDSPLIT:
                /*
                 * We have to split the page.  Back out the cursor setup,
                 * discard the stack of pages, and do the split.
                 */
-               if (replace) {
-                       replace = 0;
+               if (isdeleted)
                        __bam_ca_replace(dbp, h->pgno, indx, REPLACE_FAILED);
-               }
 
                (void)__bam_stkrel(dbp);
                stack = 0;
@@ -225,7 +219,7 @@ retry:      /*
                goto retry;
                /* NOTREACHED */
        default:
-               if (replace)
+               if (isdeleted)
                        __bam_ca_replace(dbp, h->pgno, indx, REPLACE_FAILED);
                break;
        }
@@ -393,7 +387,8 @@ __bam_lookup(dbp, key, exactp)
                                for (indx = 0;
                                    indx < (db_indx_t)(NUM_ENT(h) - P_INDX) &&
                                    h->inp[indx] == h->inp[indx + P_INDX];
-                                   indx += P_INDX);
+                                   indx += P_INDX)
+                                       ;
                                e.indx = indx;
                        }
                        goto fast;
@@ -427,7 +422,7 @@ slow:       return (__bam_search(dbp, key, S_INSERT, 1, NULL, exactp));
  *     Insert an item into the tree.
  *
  * PUBLIC: int __bam_iitem __P((DB *,
- * PUBLIC:    PAGE **, db_indx_t *, DBT *, DBT *, int, int));
+ * PUBLIC:    PAGE **, db_indx_t *, DBT *, DBT *, u_int32_t, u_int32_t));
  */
 int
 __bam_iitem(dbp, hp, indxp, key, data, op, flags)
@@ -435,13 +430,13 @@ __bam_iitem(dbp, hp, indxp, key, data, op, flags)
        PAGE **hp;
        db_indx_t *indxp;
        DBT *key, *data;
-       int op, flags;
+       u_int32_t op, flags;
 {
        BTREE *t;
        BKEYDATA *bk;
        DBT tdbt;
        PAGE *h;
-       db_indx_t indx;
+       db_indx_t indx, nbytes;
        u_int32_t data_size, have_bytes, need_bytes, needed;
        int bigkey, bigdata, dupadjust, replace, ret;
 
@@ -466,12 +461,27 @@ __bam_iitem(dbp, hp, indxp, key, data, op, flags)
                        ++*indxp;
 
                /* Remove the current item if it's a DB_CURRENT op. */
-               if (op == DB_CURRENT && (ret = __db_ditem(dbp, *hp, *indxp,
-                   BKEYDATA_SIZE(GET_BKEYDATA(*hp, *indxp)->len))) != 0)
-                       return (ret);
+               if (op == DB_CURRENT) {
+                       bk = GET_BKEYDATA(*hp, *indxp);
+                       switch (B_TYPE(bk->type)) {
+                       case B_KEYDATA:
+                               nbytes = BKEYDATA_SIZE(bk->len);
+                               break;
+                       case B_OVERFLOW:
+                               nbytes = BOVERFLOW_SIZE;
+                               break;
+                       default:
+                               return (__db_pgfmt(dbp, h->pgno));
+                       }
+                       if ((ret = __db_ditem(dbp, *hp, *indxp, nbytes)) != 0)
+                               return (ret);
+               }
 
                /* Put the new/replacement item onto the page. */
-               return (__db_dput(dbp, data, hp, indxp, __bam_new));
+               if ((ret = __db_dput(dbp, data, hp, indxp, __bam_new)) != 0)
+                       return (ret);
+
+               goto done;
        }
 
        /* Handle fixed-length records: build the real record. */
@@ -568,7 +578,7 @@ __bam_iitem(dbp, hp, indxp, key, data, op, flags)
                case DB_BEFORE:         /* 2. Insert a new key/data pair. */
                        break;
                default:
-                       abort();
+                       return (EINVAL);
                }
 
                /* Add the key. */
@@ -638,7 +648,7 @@ __bam_iitem(dbp, hp, indxp, key, data, op, flags)
                        replace = 1;
                        break;
                default:
-                       abort();
+                       return (EINVAL);
                }
        }
 
@@ -666,9 +676,8 @@ __bam_iitem(dbp, hp, indxp, key, data, op, flags)
                        return (ret);
        }
 
-       ++t->lstat.bt_added;
-
-       ret = memp_fset(dbp->mpf, h, DB_MPOOL_DIRTY);
+       if ((ret = memp_fset(dbp->mpf, h, DB_MPOOL_DIRTY)) != 0)
+               return (ret);
 
        /*
         * If the page is at least 50% full, and we added a duplicate, see if
@@ -681,9 +690,25 @@ __bam_iitem(dbp, hp, indxp, key, data, op, flags)
                        return (ret);
        }
 
+       /*
+        * If we've changed the record count, update the tree.  Record counts
+        * need to be updated in recno databases and in btree databases where
+        * we are supporting records.  In both cases, adjust the count if the
+        * operation wasn't performed on the current record or when the caller
+        * overrides and wants the adjustment made regardless.
+        */
+done:  if (LF_ISSET(BI_DOINCR) ||
+           (op != DB_CURRENT &&
+           (F_ISSET(dbp, DB_BT_RECNUM) || dbp->type == DB_RECNO)))
+               if ((ret = __bam_adjust(dbp, t, 1)) != 0)
+                       return (ret);
+
+       /* If we've modified a recno file, set the flag */
        if (t->bt_recno != NULL)
                F_SET(t->bt_recno, RECNO_MODIFIED);
 
+       ++t->lstat.bt_added;
+
        return (ret);
 }
 
@@ -1036,8 +1061,8 @@ __bam_partial(dbp, dbt, h, indx, nbytes)
        BOVERFLOW *bo;
        DBT copy;
        u_int32_t len, tlen;
-       int ret;
        u_int8_t *p;
+       int ret;
 
        COMPQUIET(bo, NULL);
 
@@ -1065,59 +1090,62 @@ __bam_partial(dbp, dbt, h, indx, nbytes)
                bk->len = 0;
        }
 
-       /* We use nul bytes for extending the record, get it over with. */
+       /*
+        * We use nul bytes for any part of the record that isn't specified,
+        * get it over with.
+        */
        memset(t->bt_rdata.data, 0, nbytes);
 
-       tlen = 0;
        if (B_TYPE(bk->type) == B_OVERFLOW) {
-               /* Take up to doff bytes from the record. */
+               /*
+                * In the case of an overflow record, we shift things around
+                * in the current record rather than allocate a separate copy.
+                */
                memset(&copy, 0, sizeof(copy));
                if ((ret = __db_goff(dbp, &copy, bo->tlen,
                    bo->pgno, &t->bt_rdata.data, &t->bt_rdata.ulen)) != 0)
                        return (ret);
-               tlen += dbt->doff;
+
+               /* Skip any leading data from the original record. */
+               tlen = dbt->doff;
+               p = (u_int8_t *)t->bt_rdata.data + dbt->doff;
 
                /*
-                * If the original record was larger than the offset:
-                *      If dlen > size, shift the remaining data down.
-                *      If dlen < size, shift the remaining data up.
+                * Copy in any trailing data from the original record.
+                *
+                * If the original record was larger than the original offset
+                * plus the bytes being deleted, there is trailing data in the
+                * original record we need to preserve.  If we aren't deleting
+                * the same number of bytes as we're inserting, copy it up or
+                * down, into place.
+                *
                 * Use memmove(), the regions may overlap.
                 */
-               p = t->bt_rdata.data;
-               if (bo->tlen > dbt->doff)
-                       if (dbt->dlen > dbt->size) {
-                               tlen += len = bo->tlen -
-                                   dbt->doff - (dbt->dlen - dbt->size);
-                               memmove(p + dbt->doff + dbt->size,
-                                   p + dbt->doff + dbt->dlen, len);
-                       } else if (dbt->dlen < dbt->size) {
-                               tlen += len = bo->tlen -
-                                   dbt->doff - (dbt->size - dbt->dlen);
-                               memmove(p + dbt->doff + dbt->dlen,
-                                   p + dbt->doff + dbt->size, len);
-                       } else
-                               tlen += bo->tlen - dbt->doff;
+               if (bo->tlen > dbt->doff + dbt->dlen) {
+                       len = bo->tlen - (dbt->doff + dbt->dlen);
+                       if (dbt->dlen != dbt->size)
+                               memmove(p + dbt->size, p + dbt->dlen, len);
+                       tlen += len;
+               }
 
-               /* Copy in the user's data. */
-               memcpy((u_int8_t *)t->bt_rdata.data + dbt->doff,
-                   dbt->data, dbt->size);
+               /* Copy in the application provided data. */
+               memcpy(p, dbt->data, dbt->size);
                tlen += dbt->size;
        } else {
-               /* Take up to doff bytes from the record. */
+               /* Copy in any leading data from the original record. */
                memcpy(t->bt_rdata.data,
                    bk->data, dbt->doff > bk->len ? bk->len : dbt->doff);
-               tlen += dbt->doff;
+               tlen = dbt->doff;
+               p = (u_int8_t *)t->bt_rdata.data + dbt->doff;
 
-               /* Copy in the user's data. */
-               memcpy((u_int8_t *)t->bt_rdata.data +
-                   dbt->doff, dbt->data, dbt->size);
+               /* Copy in the application provided data. */
+               memcpy(p, dbt->data, dbt->size);
                tlen += dbt->size;
 
-               /* Copy in any remaining data. */
+               /* Copy in any trailing data from the original record. */
                len = dbt->doff + dbt->dlen;
                if (bk->len > len) {
-                       memcpy((u_int8_t *)t->bt_rdata.data + dbt->doff +
-                           dbt->size, bk->data + len, bk->len - len);
+                       memcpy(p + dbt->size, bk->data + len, bk->len - len);
                        tlen += bk->len - len;
                }
        }
index 90ee137..fe33825 100644 (file)
@@ -1,23 +1,20 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 1996, 1997
+ * Copyright (c) 1996, 1997, 1998
  *     Sleepycat Software.  All rights reserved.
  */
 
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)bt_rec.c     10.18 (Sleepycat) 12/15/97";
+static const char sccsid[] = "@(#)bt_rec.c     10.21 (Sleepycat) 4/28/98";
 #endif /* not lint */
 
 #ifndef NO_SYSTEM_INCLUDES
 #include <sys/types.h>
 
-#include <ctype.h>
 #include <errno.h>
-#include <stddef.h>
-#include <stdlib.h>
 #include <string.h>
 #endif
 
@@ -27,7 +24,6 @@ static const char sccsid[] = "@(#)bt_rec.c    10.18 (Sleepycat) 12/15/97";
 #include "hash.h"
 #include "btree.h"
 #include "log.h"
-#include "db_dispatch.h"
 #include "common_ext.h"
 
 /*
@@ -51,7 +47,7 @@ __bam_pg_alloc_recover(logp, dbtp, lsnp, redo, info)
        PAGE *pagep;
        DB *file_dbp, *mdbp;
        db_pgno_t pgno;
-       int cmp_n, cmp_p, created, modified, ret;
+       int cmp_n, cmp_p, modified, ret;
 
        REC_PRINT(__bam_pg_alloc_print);
        REC_INTRO(__bam_pg_alloc_read);
@@ -86,18 +82,17 @@ __bam_pg_alloc_recover(logp, dbtp, lsnp, redo, info)
        }
 
        /* Fix up the allocated page. */
-       created = IS_ZERO_LSN(LSN(pagep));
        modified = 0;
        cmp_n = log_compare(lsnp, &LSN(pagep));
        cmp_p = log_compare(&LSN(pagep), &argp->page_lsn);
-       if ((created || cmp_p == 0) && redo) {
+       if (cmp_p == 0 && redo) {
                /* Need to redo update described. */
                P_INIT(pagep, file_dbp->pgsize,
                    argp->pgno, PGNO_INVALID, PGNO_INVALID, 0, argp->ptype);
 
                pagep->lsn = *lsnp;
                modified = 1;
-       } else if ((created || cmp_n == 0) && !redo) {
+       } else if (cmp_n == 0 && !redo) {
                /* Need to undo update described. */
                P_INIT(pagep, file_dbp->pgsize,
                    argp->pgno, PGNO_INVALID, meta->free, 0, P_INVALID);
index 70ab63b..38dbbd1 100644 (file)
@@ -1,14 +1,14 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 1997
+ * Copyright (c) 1997, 1998
  *     Sleepycat Software.  All rights reserved.
  */
 
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)bt_recno.c   10.26 (Sleepycat) 1/8/98";
+static const char sccsid[] = "@(#)bt_recno.c   10.37 (Sleepycat) 5/23/98";
 #endif /* not lint */
 
 #ifndef NO_SYSTEM_INCLUDES
@@ -16,8 +16,6 @@ static const char sccsid[] = "@(#)bt_recno.c  10.26 (Sleepycat) 1/8/98";
 
 #include <errno.h>
 #include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
 #include <string.h>
 #endif
 
@@ -25,16 +23,17 @@ static const char sccsid[] = "@(#)bt_recno.c        10.26 (Sleepycat) 1/8/98";
 #include "db_page.h"
 #include "btree.h"
 
-static int __ram_add __P((DB *, db_recno_t *, DBT *, int, int));
+static int __ram_add __P((DB *, db_recno_t *, DBT *, u_int32_t, u_int32_t));
 static int __ram_c_close __P((DBC *));
-static int __ram_c_del __P((DBC *, int));
-static int __ram_c_get __P((DBC *, DBT *, DBT *, int));
-static int __ram_c_put __P((DBC *, DBT *, DBT *, int));
+static int __ram_c_del __P((DBC *, u_int32_t));
+static int __ram_c_get __P((DBC *, DBT *, DBT *, u_int32_t));
+static int __ram_c_put __P((DBC *, DBT *, DBT *, u_int32_t));
 static int __ram_fmap __P((DB *, db_recno_t));
-static int __ram_get __P((DB *, DB_TXN *, DBT *, DBT *, int));
-static int __ram_put __P((DB *, DB_TXN *, DBT *, DBT *, int));
+static int __ram_get __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t));
+static int __ram_iget __P((DB *, DBT *, DBT *));
+static int __ram_put __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t));
 static int __ram_source __P((DB *, RECNO *, const char *));
-static int __ram_sync __P((DB *, int));
+static int __ram_sync __P((DB *, u_int32_t));
 static int __ram_update __P((DB *, db_recno_t, int));
 static int __ram_vmap __P((DB *, db_recno_t));
 static int __ram_writeback __P((DB *));
@@ -142,7 +141,7 @@ __ram_open(dbp, type, dbinfo)
 
 err:   /* If we mmap'd a source file, discard it. */
        if (rp->re_smap != NULL)
-               (void)__db_unmap(rp->re_smap, rp->re_msize);
+               (void)__db_unmapfile(rp->re_smap, rp->re_msize);
 
        /* If we opened a source file, discard it. */
        if (rp->re_fd != -1)
@@ -199,9 +198,9 @@ __ram_cursor(dbp, txn, dbcp)
         * All cursors are queued from the master DB structure.  Add the
         * cursor to that queue.
         */
-       DB_THREAD_LOCK(dbp);
+       CURSOR_SETUP(dbp);
        TAILQ_INSERT_HEAD(&dbp->curs_queue, dbc, links);
-       DB_THREAD_UNLOCK(dbp);
+       CURSOR_TEARDOWN(dbp);
 
        *dbcp = dbc;
        return (0);
@@ -216,16 +215,10 @@ __ram_get(argdbp, txn, key, data, flags)
        DB *argdbp;
        DB_TXN *txn;
        DBT *key, *data;
-       int flags;
+       u_int32_t flags;
 {
-       BTREE *t;
        DB *dbp;
-       PAGE *h;
-       db_indx_t indx;
-       db_recno_t recno;
-       int exact, ret, stack;
-
-       stack = 0;
+       int ret;
 
        DEBUG_LWRITE(argdbp, txn, "ram_get", key, NULL, flags);
 
@@ -234,6 +227,30 @@ __ram_get(argdbp, txn, key, data, flags)
                return (ret);
 
        GETHANDLE(argdbp, txn, &dbp, ret);
+
+       ret = __ram_iget(dbp, key, data);
+
+       PUTHANDLE(dbp);
+       return (ret);
+}
+
+/*
+ * __ram_iget --
+ *     Internal ram get function, called for both standard and cursor
+ *     get after the flags have been checked.
+ */
+static int
+__ram_iget(dbp, key, data)
+       DB *dbp;
+       DBT *key, *data;
+{
+       BTREE *t;
+       PAGE *h;
+       db_indx_t indx;
+       db_recno_t recno;
+       int exact, ret, stack;
+
+       stack = 0;
        t = dbp->internal;
 
        /* Check the user's record number and fill in as necessary. */
@@ -265,7 +282,6 @@ done:       /* Discard the stack. */
        if (stack)
                __bam_stkrel(dbp);
 
-       PUTHANDLE(dbp);
        return (ret);
 }
 
@@ -278,7 +294,7 @@ __ram_put(argdbp, txn, key, data, flags)
        DB *argdbp;
        DB_TXN *txn;
        DBT *key, *data;
-       int flags;
+       u_int32_t flags;
 {
        BTREE *t;
        DB *dbp;
@@ -324,7 +340,7 @@ __ram_put(argdbp, txn, key, data, flags)
 static int
 __ram_sync(argdbp, flags)
        DB *argdbp;
-       int flags;
+       u_int32_t flags;
 {
        DB *dbp;
        int ret;
@@ -361,7 +377,7 @@ __ram_close(argdbp)
 
        /* Close any underlying mmap region. */
        if (rp->re_smap != NULL)
-               (void)__db_unmap(rp->re_smap, rp->re_msize);
+               (void)__db_unmapfile(rp->re_smap, rp->re_msize);
 
        /* Close any backing source file descriptor. */
        if (rp->re_fd != -1)
@@ -403,17 +419,10 @@ __ram_c_iclose(dbp, dbc)
        DB *dbp;
        DBC *dbc;
 {
-       /*
-        * All cursors are queued from the master DB structure.  For
-        * now, discard the DB handle which triggered this call, and
-        * replace it with the cursor's reference.
-        */
-       dbp = dbc->dbp;
-
        /* Remove the cursor from the queue. */
-       DB_THREAD_LOCK(dbp);
+       CURSOR_SETUP(dbp);
        TAILQ_REMOVE(&dbp->curs_queue, dbc, links);
-       DB_THREAD_UNLOCK(dbp);
+       CURSOR_TEARDOWN(dbp);
 
        /* Discard the structures. */
        FREE(dbc->internal, sizeof(RCURSOR));
@@ -429,7 +438,7 @@ __ram_c_iclose(dbp, dbc)
 static int
 __ram_c_del(dbc, flags)
        DBC *dbc;
-       int flags;
+       u_int32_t flags;
 {
        DBT key;
        RCURSOR *cp;
@@ -466,7 +475,7 @@ static int
 __ram_c_get(dbc, key, data, flags)
        DBC *dbc;
        DBT *key, *data;
-       int flags;
+       u_int32_t flags;
 {
        BTREE *t;
        DB *dbp;
@@ -537,7 +546,7 @@ retry:      /* Update the record number. */
 
        /*
         * Return the key if the user didn't give us one, and then pass it
-        * into __ram_get().
+        * into __ram_iget().
         */
        if (flags != DB_SET && flags != DB_SET_RANGE &&
            (ret = __db_retcopy(key, &cp->recno, sizeof(cp->recno),
@@ -555,7 +564,7 @@ retry:      /* Update the record number. */
         *
         * Skip any keys that don't really exist.
         */
-       if ((ret = __ram_get(dbp, dbc->txn, key, data, 0)) != 0)
+       if ((ret = __ram_iget(dbp, key, data)) != 0)
                if (ret == DB_KEYEMPTY &&
                    (flags == DB_NEXT || flags == DB_PREV))
                        goto retry;
@@ -575,7 +584,7 @@ static int
 __ram_c_put(dbc, key, data, flags)
        DBC *dbc;
        DBT *key, *data;
-       int flags;
+       u_int32_t flags;
 {
        BTREE *t;
        RCURSOR *cp, copy;
@@ -624,28 +633,21 @@ split:            arg = &cp->recno;
        if ((ret = __bam_stkrel(dbp)) != 0)
                goto err;
 
-       if (flags != DB_CURRENT) {
-               /* Adjust the counts. */
-               if ((ret = __bam_adjust(dbp, t, 1)) != 0)
-                       goto err;
-
-               switch (flags) {
-               case DB_AFTER:
-                       /* Adjust the cursors. */
-                       __ram_ca(dbp, cp->recno, CA_IAFTER);
-
-                       /* Set this cursor to reference the new record. */
-                       cp->recno = copy.recno + 1;
-                       break;
-               case DB_BEFORE:
-                       /* Adjust the cursors. */
-                       __ram_ca(dbp, cp->recno, CA_IBEFORE);
+       switch (flags) {
+       case DB_AFTER:
+               /* Adjust the cursors. */
+               __ram_ca(dbp, cp->recno, CA_IAFTER);
 
-                       /* Set this cursor to reference the new record. */
-                       cp->recno = copy.recno;
-                       break;
-               }
+               /* Set this cursor to reference the new record. */
+               cp->recno = copy.recno + 1;
+               break;
+       case DB_BEFORE:
+               /* Adjust the cursors. */
+               __ram_ca(dbp, cp->recno, CA_IBEFORE);
 
+               /* Set this cursor to reference the new record. */
+               cp->recno = copy.recno;
+               break;
        }
 
        /*
@@ -679,7 +681,7 @@ __ram_ca(dbp, recno, op)
        /*
         * Adjust the cursors.  See the comment in __bam_ca_delete().
         */
-       DB_THREAD_LOCK(dbp);
+       CURSOR_SETUP(dbp);
        for (dbc = TAILQ_FIRST(&dbp->curs_queue);
            dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
                cp = (RCURSOR *)dbc->internal;
@@ -698,7 +700,7 @@ __ram_ca(dbp, recno, op)
                        break;
                }
        }
-       DB_THREAD_UNLOCK(dbp);
+       CURSOR_TEARDOWN(dbp);
 }
 
 #ifdef DEBUG
@@ -715,14 +717,15 @@ __ram_cprint(dbp)
        DBC *dbc;
        RCURSOR *cp;
 
-       DB_THREAD_LOCK(dbp);
+       CURSOR_SETUP(dbp);
        for (dbc = TAILQ_FIRST(&dbp->curs_queue);
            dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
                cp = (RCURSOR *)dbc->internal;
                fprintf(stderr,
                    "%#0x: recno: %lu\n", (u_int)cp, (u_long)cp->recno);
        }
-       DB_THREAD_UNLOCK(dbp);
+       CURSOR_TEARDOWN(dbp);
+
        return (0);
 }
 #endif /* DEBUG */
@@ -853,11 +856,11 @@ __ram_source(dbp, rp, fname)
        const char *fname;
 {
        size_t size;
-       u_int32_t mbytes, bytes;
-       int oflags, ret;
+       u_int32_t bytes, mbytes, oflags;
+       int ret;
 
        if ((ret = __db_appname(dbp->dbenv,
-           DB_APP_DATA, NULL, fname, NULL, &rp->re_source)) != 0)
+           DB_APP_DATA, NULL, fname, 0, NULL, &rp->re_source)) != 0)
                return (ret);
 
        oflags = F_ISSET(dbp, DB_AM_RDONLY) ? DB_RDONLY : 0;
@@ -886,7 +889,8 @@ __ram_source(dbp, rp, fname)
        }
 
        size = mbytes * MEGABYTE + bytes;
-       if ((ret = __db_map(rp->re_fd, (size_t)size, 1, 1, &rp->re_smap)) != 0)
+       if ((ret = __db_mapfile(rp->re_source,
+           rp->re_fd, (size_t)size, 1, &rp->re_smap)) != 0)
                goto err;
        rp->re_cmap = rp->re_smap;
        rp->re_emap = (u_int8_t *)rp->re_smap + (rp->re_msize = size);
@@ -952,7 +956,7 @@ __ram_writeback(dbp)
         * open will fail.
         */
        if (rp->re_smap != NULL) {
-               (void)__db_unmap(rp->re_smap, rp->re_msize);
+               (void)__db_unmapfile(rp->re_smap, rp->re_msize);
                rp->re_smap = NULL;
        }
 
@@ -1078,19 +1082,22 @@ __ram_fmap(dbp, top)
 
        sp = (u_int8_t *)rp->re_cmap;
        ep = (u_int8_t *)rp->re_emap;
-       while (recno <= top) {
+       while (recno < top) {
                if (sp >= ep) {
                        F_SET(rp, RECNO_EOF);
                        return (DB_NOTFOUND);
                }
                len = rp->re_len;
                for (p = t->bt_rdata.data;
-                   sp < ep && len > 0; *p++ = *sp++, --len);
+                   sp < ep && len > 0; *p++ = *sp++, --len)
+                       ;
 
                /*
-                * Another process may have read some portion of the input
-                * file already, in which case we just want to discard the
-                * new record.
+                * Another process may have read this record from the input
+                * file and stored it into the database already, in which
+                * case we don't need to repeat that operation.  We detect
+                * this by checking if the last record we've read is greater
+                * or equal to the number of records in the database.
                 *
                 * XXX
                 * We should just do a seek, since the records are fixed
@@ -1138,17 +1145,20 @@ __ram_vmap(dbp, top)
 
        sp = (u_int8_t *)rp->re_cmap;
        ep = (u_int8_t *)rp->re_emap;
-       while (recno <= top) {
+       while (recno < top) {
                if (sp >= ep) {
                        F_SET(rp, RECNO_EOF);
                        return (DB_NOTFOUND);
                }
-               for (data.data = sp; sp < ep && *sp != delim; ++sp);
+               for (data.data = sp; sp < ep && *sp != delim; ++sp)
+                       ;
 
                /*
-                * Another process may have read some portion of the input
-                * file already, in which case we just want to discard the
-                * new record.
+                * Another process may have read this record from the input
+                * file and stored it into the database already, in which
+                * case we don't need to repeat that operation.  We detect
+                * this by checking if the last record we've read is greater
+                * or equal to the number of records in the database.
                 */
                if (rp->re_last >= recno) {
                        data.size = sp - (u_int8_t *)data.data;
@@ -1172,12 +1182,13 @@ __ram_add(dbp, recnop, data, flags, bi_flags)
        DB *dbp;
        db_recno_t *recnop;
        DBT *data;
-       int flags, bi_flags;
+       u_int32_t flags, bi_flags;
 {
+       BKEYDATA *bk;
        BTREE *t;
        PAGE *h;
        db_indx_t indx;
-       int exact, ret, stack;
+       int exact, isdeleted, ret, stack;
 
        t = dbp->internal;
 
@@ -1190,34 +1201,63 @@ retry:  /* Find the slot for insertion. */
        stack = 1;
 
        /*
-        * The recno access method doesn't currently support duplicates, so
-        * if an identical key is already in the tree we're either overwriting
-        * it or an error is returned.
+        * If DB_NOOVERWRITE is set and the item already exists in the tree,
+        * return an error unless the item has been marked for deletion.
         */
-       if (exact && LF_ISSET(DB_NOOVERWRITE)) {
-               ret = DB_KEYEXIST;
-               goto err;
+       isdeleted = 0;
+       if (exact) {
+               bk = GET_BKEYDATA(h, indx);
+               if (B_DISSET(bk->type)) {
+                       isdeleted = 1;
+                       __bam_ca_replace(dbp, h->pgno, indx, REPLACE_SETUP);
+               } else
+                       if (LF_ISSET(DB_NOOVERWRITE)) {
+                               ret = DB_KEYEXIST;
+                               goto err;
+                       }
        }
 
        /*
         * Select the arguments for __bam_iitem() and do the insert.  If the
         * key is an exact match, or we're replacing the data item with a
-        * new data item.  If the key isn't an exact match, we're inserting
-        * a new key/data pair, before the search location.
+        * new data item, replace the current item.  If the key isn't an exact
+        * match, we're inserting a new key/data pair, before the search
+        * location.
         */
-       if ((ret = __bam_iitem(dbp, &h, &indx, NULL,
-           data, exact ? DB_CURRENT : DB_BEFORE, bi_flags)) == DB_NEEDSPLIT) {
+       switch (ret = __bam_iitem(dbp,
+           &h, &indx, NULL, data, exact ? DB_CURRENT : DB_BEFORE, bi_flags)) {
+       case 0:
+               /*
+                * Done.  Clean up the cursor and adjust the internal page
+                * counts.
+                */
+               if (isdeleted)
+                       __bam_ca_replace(dbp, h->pgno, indx, REPLACE_SUCCESS);
+               break;
+       case DB_NEEDSPLIT:
+               /*
+                * We have to split the page.  Back out the cursor setup,
+                * discard the stack of pages, and do the split.
+                */
+               if (isdeleted)
+                       __bam_ca_replace(dbp, h->pgno, indx, REPLACE_FAILED);
+
                (void)__bam_stkrel(dbp);
                stack = 0;
+
                if ((ret = __bam_split(dbp, recnop)) != 0)
-                       goto err;
+                       break;
+
                goto retry;
+               /* NOTREACHED */
+       default:
+               if (isdeleted)
+                       __bam_ca_replace(dbp, h->pgno, indx, REPLACE_FAILED);
+               break;
        }
 
-       if (!exact && ret == 0)
-               __bam_adjust(dbp, t, 1);
-
 err:   if (stack)
                __bam_stkrel(dbp);
+
        return (ret);
 }
index ee26221..caa6b35 100644 (file)
@@ -1,7 +1,7 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 1996, 1997
+ * Copyright (c) 1996, 1997, 1998
  *     Sleepycat Software.  All rights reserved.
  */
 /*
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)bt_rsearch.c 10.8 (Sleepycat) 8/24/97";
+static const char sccsid[] = "@(#)bt_rsearch.c 10.15 (Sleepycat) 5/6/98";
 #endif /* not lint */
 
 #ifndef NO_SYSTEM_INCLUDES
 #include <sys/types.h>
-
-#include <stdio.h>
-#include <stdlib.h>
 #endif
 
 #include "db_int.h"
@@ -62,13 +59,13 @@ static const char sccsid[] = "@(#)bt_rsearch.c      10.8 (Sleepycat) 8/24/97";
  * __bam_rsearch --
  *     Search a btree for a record number.
  *
- * PUBLIC: int __bam_rsearch __P((DB *, db_recno_t *, u_int, int, int *));
+ * PUBLIC: int __bam_rsearch __P((DB *, db_recno_t *, u_int32_t, int, int *));
  */
 int
 __bam_rsearch(dbp, recnop, flags, stop, exactp)
        DB *dbp;
        db_recno_t *recnop;
-       u_int flags;
+       u_int32_t flags;
        int stop, *exactp;
 {
        BINTERNAL *bi;
@@ -78,7 +75,7 @@ __bam_rsearch(dbp, recnop, flags, stop, exactp)
        RINTERNAL *ri;
        db_indx_t indx, top;
        db_pgno_t pg;
-       db_recno_t recno, total;
+       db_recno_t i, recno, total;
        int isappend, ret, stack;
 
        t = dbp->internal;
@@ -136,8 +133,7 @@ __bam_rsearch(dbp, recnop, flags, stop, exactp)
                        *exactp = 1;
                else {
                        *exactp = 0;
-                       if (flags == S_DELETE ||
-                           flags == S_FIND || recno > total + 1) {
+                       if (!PAST_END_OK(flags) || recno > total + 1) {
                                (void)memp_fput(dbp->mpf, h, 0);
                                (void)__BT_LPUT(dbp, lock);
                                return (DB_NOTFOUND);
@@ -164,30 +160,65 @@ __bam_rsearch(dbp, recnop, flags, stop, exactp)
                stack = 1;
        }
 
-       /* Records in the tree are 0-based, and record numbers are 1-based. */
-       --recno;
-
+       /*
+        * !!!
+        * Record numbers in the tree are 0-based, but the recno is
+        * 1-based.  All of the calculations below have to take this
+        * into account.
+        */
        for (total = 0;;) {
                switch (TYPE(h)) {
                case P_LBTREE:
-                       BT_STK_ENTER(t, h, (recno - total) * P_INDX, lock, ret);
+                       recno -= total;
+
+                       /*
+                        * There may be logically deleted records on the page,
+                        * walk the page correcting for them.  The record may
+                        * not exist if there are enough deleted records in the
+                        * page.
+                        */
+                       if (recno <= NUM_ENT(h))
+                               for (i = recno - 1;; --i) {
+                                       if (B_DISSET(GET_BKEYDATA(h,
+                                           i * P_INDX + O_INDX)->type))
+                                               ++recno;
+                                       if (i == 0)
+                                               break;
+                               }
+                       if (recno > NUM_ENT(h)) {
+                               *exactp = 0;
+                               if (!PAST_END_OK(flags) ||
+                                   recno > (db_recno_t)(NUM_ENT(h) + 1)) {
+                                       ret = DB_NOTFOUND;
+                                       goto err;
+                               }
+
+                       }
+
+                       /* Correct from 1-based to 0-based for a page offset. */
+                       --recno;
+                       BT_STK_ENTER(t, h, recno * P_INDX, lock, ret);
                        return (ret);
                case P_IBTREE:
                        for (indx = 0, top = NUM_ENT(h);;) {
                                bi = GET_BINTERNAL(h, indx);
-                               if (++indx == top || total + bi->nrecs > recno)
+                               if (++indx == top || total + bi->nrecs >= recno)
                                        break;
                                total += bi->nrecs;
                        }
                        pg = bi->pgno;
                        break;
                case P_LRECNO:
-                       BT_STK_ENTER(t, h, recno - total, lock, ret);
+                       recno -= total;
+
+                       /* Correct from 1-based to 0-based for a page offset. */
+                       --recno;
+                       BT_STK_ENTER(t, h, recno, lock, ret);
                        return (ret);
                case P_IRECNO:
                        for (indx = 0, top = NUM_ENT(h);;) {
                                ri = GET_RINTERNAL(h, indx);
-                               if (++indx == top || total + ri->nrecs > recno)
+                               if (++indx == top || total + ri->nrecs >= recno)
                                        break;
                                total += ri->nrecs;
                        }
@@ -244,13 +275,13 @@ err:      BT_STK_POP(t);
  * __bam_adjust --
  *     Adjust the tree after adding or deleting a record.
  *
- * PUBLIC: int __bam_adjust __P((DB *, BTREE *, int));
+ * PUBLIC: int __bam_adjust __P((DB *, BTREE *, int32_t));
  */
 int
 __bam_adjust(dbp, t, adjust)
        DB *dbp;
        BTREE *t;
-       int adjust;
+       int32_t adjust;
 {
        EPG *epg;
        PAGE *h;
@@ -264,7 +295,7 @@ __bam_adjust(dbp, t, adjust)
                            (ret = __bam_cadjust_log(dbp->dbenv->lg_info,
                            dbp->txn, &LSN(h), 0, dbp->log_fileid,
                            PGNO(h), &LSN(h), (u_int32_t)epg->indx,
-                           (int32_t)adjust, 1)) != 0)
+                           adjust, 1)) != 0)
                                return (ret);
 
                        if (TYPE(h) == P_IBTREE)
@@ -322,26 +353,31 @@ db_recno_t
 __bam_total(h)
        PAGE *h;
 {
-       db_recno_t recs;
-       db_indx_t nxt, top;
+       db_recno_t nrecs;
+       db_indx_t indx, top;
+
+       nrecs = 0;
+       top = NUM_ENT(h);
 
        switch (TYPE(h)) {
        case P_LBTREE:
-               recs = NUM_ENT(h) / 2;
+               /* Check for logically deleted records. */
+               for (indx = 0; indx < top; indx += P_INDX)
+                       if (!B_DISSET(GET_BKEYDATA(h, indx + O_INDX)->type))
+                               ++nrecs;
                break;
        case P_IBTREE:
-               for (recs = 0, nxt = 0, top = NUM_ENT(h); nxt < top; ++nxt)
-                       recs += GET_BINTERNAL(h, nxt)->nrecs;
+               for (indx = 0; indx < top; indx += O_INDX)
+                       nrecs += GET_BINTERNAL(h, indx)->nrecs;
                break;
        case P_LRECNO:
-               recs = NUM_ENT(h);
+               nrecs = NUM_ENT(h);
                break;
        case P_IRECNO:
-               for (recs = 0, nxt = 0, top = NUM_ENT(h); nxt < top; ++nxt)
-                       recs += GET_RINTERNAL(h, nxt)->nrecs;
+               for (indx = 0; indx < top; indx += O_INDX)
+                       nrecs += GET_RINTERNAL(h, indx)->nrecs;
                break;
-       default:
-               abort();
        }
-       return (recs);
+
+       return (nrecs);
 }
index c39c9af..09ce46d 100644 (file)
@@ -1,7 +1,7 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 1996, 1997
+ * Copyright (c) 1996, 1997, 1998
  *     Sleepycat Software.  All rights reserved.
  */
 /*
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)bt_search.c  10.9 (Sleepycat) 11/18/97";
+static const char sccsid[] = "@(#)bt_search.c  10.15 (Sleepycat) 5/6/98";
 #endif /* not lint */
 
 #ifndef NO_SYSTEM_INCLUDES
 #include <sys/types.h>
 
 #include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
 #include <string.h>
 #endif
 
@@ -68,13 +66,13 @@ static const char sccsid[] = "@(#)bt_search.c       10.9 (Sleepycat) 11/18/97";
  *     Search a btree for a key.
  *
  * PUBLIC: int __bam_search __P((DB *,
- * PUBLIC:     const DBT *, u_int, int, db_recno_t *, int *));
+ * PUBLIC:     const DBT *, u_int32_t, int, db_recno_t *, int *));
  */
 int
 __bam_search(dbp, key, flags, stop, recnop, exactp)
        DB *dbp;
        const DBT *key;
-       u_int flags;
+       u_int32_t flags;
        int stop, *exactp;
        db_recno_t *recnop;
 {
@@ -109,8 +107,7 @@ __bam_search(dbp, key, flags, stop, recnop, exactp)
         * Retrieve the root page.
         */
        pg = PGNO_ROOT;
-       stack = F_ISSET(dbp, DB_BT_RECNUM) &&
-           (flags == S_INSERT || flags == S_DELETE);
+       stack = F_ISSET(dbp, DB_BT_RECNUM) && LF_ISSET(S_STACK);
        if ((ret = __bam_lget(dbp,
            0, pg, stack ? DB_LOCK_WRITE : DB_LOCK_READ, &lock)) != 0)
                return (ret);
@@ -179,6 +176,14 @@ __bam_search(dbp, key, flags, stop, recnop, exactp)
                        if (LF_ISSET(S_EXACT))
                                goto notfound;
 
+                       /*
+                        * !!!
+                        * Possibly returning a deleted record -- DB_SET_RANGE,
+                        * DB_KEYFIRST and DB_KEYLAST don't require an exact
+                        * match, and we don't want to walk multiple pages here
+                        * to find an undeleted record.  This is handled in the
+                        * __bam_c_search() routine.
+                        */
                        BT_STK_ENTER(t, h, base, lock, ret);
                        return (ret);
                }
@@ -249,7 +254,10 @@ match:     *exactp = 1;
        /*
         * If we got here, we know that we have a btree leaf page.
         *
-        * If there are duplicates, go to the first/last one.
+        * If there are duplicates, go to the first/last one.  This is
+        * safe because we know that we're not going to leave the page,
+        * all duplicate sets that are not on overflow pages exist on a
+        * single leaf page.
         */
        if (LF_ISSET(S_DUPLAST))
                while (indx < (db_indx_t)(NUM_ENT(h) - P_INDX) &&
@@ -261,8 +269,8 @@ match:      *exactp = 1;
                        indx -= P_INDX;
 
        /*
-        * Now check if we are allowed to return deleted item; if not
-        * find/last the first non-deleted item.
+        * Now check if we are allowed to return deleted items; if not
+        * find the next (or previous) non-deleted item.
         */
        if (LF_ISSET(S_DELNO)) {
                if (LF_ISSET(S_DUPLAST))
index 219d486..da9417c 100644 (file)
@@ -1,7 +1,7 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 1996, 1997
+ * Copyright (c) 1996, 1997, 1998
  *     Sleepycat Software.  All rights reserved.
  */
 /*
@@ -44,7 +44,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)bt_split.c   10.18 (Sleepycat) 11/23/97";
+static const char sccsid[] = "@(#)bt_split.c   10.23 (Sleepycat) 5/23/98";
 #endif /* not lint */
 
 #ifndef NO_SYSTEM_INCLUDES
@@ -52,8 +52,6 @@ static const char sccsid[] = "@(#)bt_split.c  10.18 (Sleepycat) 11/23/97";
 
 #include <errno.h>
 #include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
 #include <string.h>
 #endif
 
@@ -168,8 +166,10 @@ __bam_root(dbp, cp)
        t = dbp->internal;
 
        /* Yeah, right. */
-       if (cp->page->level >= MAXBTREELEVEL)
-               return (ENOSPC);
+       if (cp->page->level >= MAXBTREELEVEL) {
+               ret = ENOSPC;
+               goto err;
+       }
 
        /* Create new left and right pages for the split. */
        lp = rp = NULL;
@@ -237,18 +237,16 @@ __bam_page(dbp, pp, cp)
        DB *dbp;
        EPG *pp, *cp;
 {
-       BTREE *t;
        DB_LOCK tplock;
        PAGE *lp, *rp, *tp;
        int ret;
 
-       t = dbp->internal;
        lp = rp = tp = NULL;
        ret = -1;
 
        /* Create new right page for the split. */
        if ((ret = __bam_new(dbp, TYPE(cp->page), &rp)) != 0)
-               return (ret);
+               goto err;
        P_INIT(rp, dbp->pgsize, rp->pgno,
            ISINTERNAL(cp->page) ? PGNO_INVALID : cp->page->pgno,
            ISINTERNAL(cp->page) ? PGNO_INVALID : cp->page->next_pgno,
@@ -259,7 +257,7 @@ __bam_page(dbp, pp, cp)
                ret = ENOMEM;
                goto err;
        }
-#ifdef DEBUG
+#ifdef DIAGNOSTIC
        memset(lp, 0xff, dbp->pgsize);
 #endif
        P_INIT(lp, dbp->pgsize, cp->page->pgno,
@@ -906,13 +904,13 @@ __bam_copy(dbp, pp, cp, nxt, stop)
        PAGE *pp, *cp;
        u_int32_t nxt, stop;
 {
-       db_indx_t dup, nbytes, off;
+       db_indx_t nbytes, off;
 
        /*
         * Copy the rest of the data to the right page.  Nxt is the next
         * offset placed on the target page.
         */
-       for (dup = off = 0; nxt < stop; ++nxt, ++NUM_ENT(cp), ++off) {
+       for (off = 0; nxt < stop; ++nxt, ++NUM_ENT(cp), ++off) {
                switch (TYPE(pp)) {
                case P_IBTREE:
                        if (B_TYPE(GET_BINTERNAL(pp, nxt)->type) == B_KEYDATA)
index e88b5da..2236434 100644 (file)
@@ -1,21 +1,20 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 1996, 1997
+ * Copyright (c) 1996, 1997, 1998
  *     Sleepycat Software.  All rights reserved.
  */
 
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)bt_stat.c    10.14 (Sleepycat) 10/25/97";
+static const char sccsid[] = "@(#)bt_stat.c    10.17 (Sleepycat) 4/26/98";
 #endif /* not lint */
 
 #ifndef NO_SYSTEM_INCLUDES
 #include <sys/types.h>
 
 #include <errno.h>
-#include <stdlib.h>
 #include <string.h>
 #endif
 
@@ -29,14 +28,14 @@ static void __bam_add_rstat __P((DB_BTREE_LSTAT *, DB_BTREE_STAT *));
  * __bam_stat --
  *     Gather/print the btree statistics
  *
- * PUBLIC: int __bam_stat __P((DB *, void *, void *(*)(size_t), int));
+ * PUBLIC: int __bam_stat __P((DB *, void *, void *(*)(size_t), u_int32_t));
  */
 int
 __bam_stat(argdbp, spp, db_malloc, flags)
        DB *argdbp;
        void *spp;
        void *(*db_malloc) __P((size_t));
-       int flags;
+       u_int32_t flags;
 {
        BTMETA *meta;
        BTREE *t;
index 6145696..928dce2 100644 (file)
@@ -1,16 +1,12 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 1996, 1997
+ * Copyright (c) 1996, 1997, 1998
  *     Sleepycat Software.  All rights reserved.
+ *
+ *     @(#)btree.src   10.8 (Sleepycat) 4/10/98
  */
 
-#include "config.h"
-
-#ifndef lint
-static const char sccsid[] = "@(#)btree.src    10.6 (Sleepycat) 11/2/97";
-#endif /* not lint */
-
 PREFIX bam
 
 /*
index 18bbd5d..75eadb1 100644 (file)
@@ -15,8 +15,6 @@
 #include "db_dispatch.h"
 #include "btree.h"
 #include "db_am.h"
-#include "common_ext.h"
-
 /*
  * PUBLIC: int __bam_pg_alloc_log
  * PUBLIC:     __P((DB_LOG *, DB_TXN *, DB_LSN *, u_int32_t,
@@ -85,7 +83,7 @@ int __bam_pg_alloc_log(logp, txnid, ret_lsnp, flags,
        bp += sizeof(ptype);
        memcpy(bp, &next, sizeof(next));
        bp += sizeof(next);
-#ifdef DEBUG
+#ifdef DIAGNOSTIC
        if ((u_int32_t)(bp - (u_int8_t *)logrec.data) != logrec.size)
                fprintf(stderr, "Error in log record length");
 #endif
@@ -101,22 +99,23 @@ int __bam_pg_alloc_log(logp, txnid, ret_lsnp, flags,
  * PUBLIC:    __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
  */
 int
-__bam_pg_alloc_print(notused1, dbtp, lsnp, notused3, notused4)
+__bam_pg_alloc_print(notused1, dbtp, lsnp, notused2, notused3)
        DB_LOG *notused1;
        DBT *dbtp;
        DB_LSN *lsnp;
-       int notused3;
-       void *notused4;
+       int notused2;
+       void *notused3;
 {
        __bam_pg_alloc_args *argp;
        u_int32_t i;
-       int c, ret;
+       u_int ch;
+       int ret;
 
        i = 0;
-       c = 0;
+       ch = 0;
        notused1 = NULL;
-       notused3 = 0;
-       notused4 = NULL;
+       notused2 = 0;
+       notused3 = NULL;
 
        if ((ret = __bam_pg_alloc_read(dbtp->data, &argp)) != 0)
                return (ret);
@@ -249,7 +248,7 @@ int __bam_pg_free_log(logp, txnid, ret_lsnp, flags,
        }
        memcpy(bp, &next, sizeof(next));
        bp += sizeof(next);
-#ifdef DEBUG
+#ifdef DIAGNOSTIC
        if ((u_int32_t)(bp - (u_int8_t *)logrec.data) != logrec.size)
                fprintf(stderr, "Error in log record length");
 #endif
@@ -265,22 +264,23 @@ int __bam_pg_free_log(logp, txnid, ret_lsnp, flags,
  * PUBLIC:    __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
  */
 int
-__bam_pg_free_print(notused1, dbtp, lsnp, notused3, notused4)
+__bam_pg_free_print(notused1, dbtp, lsnp, notused2, notused3)
        DB_LOG *notused1;
        DBT *dbtp;
        DB_LSN *lsnp;
-       int notused3;
-       void *notused4;
+       int notused2;
+       void *notused3;
 {
        __bam_pg_free_args *argp;
        u_int32_t i;
-       int c, ret;
+       u_int ch;
+       int ret;
 
        i = 0;
-       c = 0;
+       ch = 0;
        notused1 = NULL;
-       notused3 = 0;
-       notused4 = NULL;
+       notused2 = 0;
+       notused3 = NULL;
 
        if ((ret = __bam_pg_free_read(dbtp->data, &argp)) != 0)
                return (ret);
@@ -297,11 +297,11 @@ __bam_pg_free_print(notused1, dbtp, lsnp, notused3, notused4)
            (u_long)argp->meta_lsn.file, (u_long)argp->meta_lsn.offset);
        printf("\theader: ");
        for (i = 0; i < argp->header.size; i++) {
-               c = ((char *)argp->header.data)[i];
-               if (isprint(c) || c == 0xa)
-                       putchar(c);
+               ch = ((u_int8_t *)argp->header.data)[i];
+               if (isprint(ch) || ch == 0xa)
+                       putchar(ch);
                else
-                       printf("%#x ", c);
+                       printf("%#x ", ch);
        }
        printf("\n");
        printf("\tnext: %lu\n", (u_long)argp->next);
@@ -443,7 +443,7 @@ int __bam_split_log(logp, txnid, ret_lsnp, flags,
                memcpy(bp, pg->data, pg->size);
                bp += pg->size;
        }
-#ifdef DEBUG
+#ifdef DIAGNOSTIC
        if ((u_int32_t)(bp - (u_int8_t *)logrec.data) != logrec.size)
                fprintf(stderr, "Error in log record length");
 #endif
@@ -459,22 +459,23 @@ int __bam_split_log(logp, txnid, ret_lsnp, flags,
  * PUBLIC:    __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
  */
 int
-__bam_split_print(notused1, dbtp, lsnp, notused3, notused4)
+__bam_split_print(notused1, dbtp, lsnp, notused2, notused3)
        DB_LOG *notused1;
        DBT *dbtp;
        DB_LSN *lsnp;
-       int notused3;
-       void *notused4;
+       int notused2;
+       void *notused3;
 {
        __bam_split_args *argp;
        u_int32_t i;
-       int c, ret;
+       u_int ch;
+       int ret;
 
        i = 0;
-       c = 0;
+       ch = 0;
        notused1 = NULL;
-       notused3 = 0;
-       notused4 = NULL;
+       notused2 = 0;
+       notused3 = NULL;
 
        if ((ret = __bam_split_read(dbtp->data, &argp)) != 0)
                return (ret);
@@ -498,11 +499,11 @@ __bam_split_print(notused1, dbtp, lsnp, notused3, notused4)
            (u_long)argp->nlsn.file, (u_long)argp->nlsn.offset);
        printf("\tpg: ");
        for (i = 0; i < argp->pg.size; i++) {
-               c = ((char *)argp->pg.data)[i];
-               if (isprint(c) || c == 0xa)
-                       putchar(c);
+               ch = ((u_int8_t *)argp->pg.data)[i];
+               if (isprint(ch) || ch == 0xa)
+                       putchar(ch);
                else
-                       printf("%#x ", c);
+                       printf("%#x ", ch);
        }
        printf("\n");
        printf("\n");
@@ -639,7 +640,7 @@ int __bam_rsplit_log(logp, txnid, ret_lsnp, flags,
        else
                memset(bp, 0, sizeof(*rootlsn));
        bp += sizeof(*rootlsn);
-#ifdef DEBUG
+#ifdef DIAGNOSTIC
        if ((u_int32_t)(bp - (u_int8_t *)logrec.data) != logrec.size)
                fprintf(stderr, "Error in log record length");
 #endif
@@ -655,22 +656,23 @@ int __bam_rsplit_log(logp, txnid, ret_lsnp, flags,
  * PUBLIC:    __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
  */
 int
-__bam_rsplit_print(notused1, dbtp, lsnp, notused3, notused4)
+__bam_rsplit_print(notused1, dbtp, lsnp, notused2, notused3)
        DB_LOG *notused1;
        DBT *dbtp;
        DB_LSN *lsnp;
-       int notused3;
-       void *notused4;
+       int notused2;
+       void *notused3;
 {
        __bam_rsplit_args *argp;
        u_int32_t i;
-       int c, ret;
+       u_int ch;
+       int ret;
 
        i = 0;
-       c = 0;
+       ch = 0;
        notused1 = NULL;
-       notused3 = 0;
-       notused4 = NULL;
+       notused2 = 0;
+       notused3 = NULL;
 
        if ((ret = __bam_rsplit_read(dbtp->data, &argp)) != 0)
                return (ret);
@@ -685,21 +687,21 @@ __bam_rsplit_print(notused1, dbtp, lsnp, notused3, notused4)
        printf("\tpgno: %lu\n", (u_long)argp->pgno);
        printf("\tpgdbt: ");
        for (i = 0; i < argp->pgdbt.size; i++) {
-               c = ((char *)argp->pgdbt.data)[i];
-               if (isprint(c) || c == 0xa)
-                       putchar(c);
+               ch = ((u_int8_t *)argp->pgdbt.data)[i];
+               if (isprint(ch) || ch == 0xa)
+                       putchar(ch);
                else
-                       printf("%#x ", c);
+                       printf("%#x ", ch);
        }
        printf("\n");
        printf("\tnrec: %lu\n", (u_long)argp->nrec);
        printf("\trootent: ");
        for (i = 0; i < argp->rootent.size; i++) {
-               c = ((char *)argp->rootent.data)[i];
-               if (isprint(c) || c == 0xa)
-                       putchar(c);
+               ch = ((u_int8_t *)argp->rootent.data)[i];
+               if (isprint(ch) || ch == 0xa)
+                       putchar(ch);
                else
-                       printf("%#x ", c);
+                       printf("%#x ", ch);
        }
        printf("\n");
        printf("\trootlsn: [%lu][%lu]\n",
@@ -817,7 +819,7 @@ int __bam_adj_log(logp, txnid, ret_lsnp, flags,
        bp += sizeof(indx_copy);
        memcpy(bp, &is_insert, sizeof(is_insert));
        bp += sizeof(is_insert);
-#ifdef DEBUG
+#ifdef DIAGNOSTIC
        if ((u_int32_t)(bp - (u_int8_t *)logrec.data) != logrec.size)
                fprintf(stderr, "Error in log record length");
 #endif
@@ -833,22 +835,23 @@ int __bam_adj_log(logp, txnid, ret_lsnp, flags,
  * PUBLIC:    __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
  */
 int
-__bam_adj_print(notused1, dbtp, lsnp, notused3, notused4)
+__bam_adj_print(notused1, dbtp, lsnp, notused2, notused3)
        DB_LOG *notused1;
        DBT *dbtp;
        DB_LSN *lsnp;
-       int notused3;
-       void *notused4;
+       int notused2;
+       void *notused3;
 {
        __bam_adj_args *argp;
        u_int32_t i;
-       int c, ret;
+       u_int ch;
+       int ret;
 
        i = 0;
-       c = 0;
+       ch = 0;
        notused1 = NULL;
-       notused3 = 0;
-       notused4 = NULL;
+       notused2 = 0;
+       notused3 = NULL;
 
        if ((ret = __bam_adj_read(dbtp->data, &argp)) != 0)
                return (ret);
@@ -975,7 +978,7 @@ int __bam_cadjust_log(logp, txnid, ret_lsnp, flags,
        bp += sizeof(adjust);
        memcpy(bp, &total, sizeof(total));
        bp += sizeof(total);
-#ifdef DEBUG
+#ifdef DIAGNOSTIC
        if ((u_int32_t)(bp - (u_int8_t *)logrec.data) != logrec.size)
                fprintf(stderr, "Error in log record length");
 #endif
@@ -991,22 +994,23 @@ int __bam_cadjust_log(logp, txnid, ret_lsnp, flags,
  * PUBLIC:    __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
  */
 int
-__bam_cadjust_print(notused1, dbtp, lsnp, notused3, notused4)
+__bam_cadjust_print(notused1, dbtp, lsnp, notused2, notused3)
        DB_LOG *notused1;
        DBT *dbtp;
        DB_LSN *lsnp;
-       int notused3;
-       void *notused4;
+       int notused2;
+       void *notused3;
 {
        __bam_cadjust_args *argp;
        u_int32_t i;
-       int c, ret;
+       u_int ch;
+       int ret;
 
        i = 0;
-       c = 0;
+       ch = 0;
        notused1 = NULL;
-       notused3 = 0;
-       notused4 = NULL;
+       notused2 = 0;
+       notused3 = NULL;
 
        if ((ret = __bam_cadjust_read(dbtp->data, &argp)) != 0)
                return (ret);
@@ -1124,7 +1128,7 @@ int __bam_cdel_log(logp, txnid, ret_lsnp, flags,
        bp += sizeof(*lsn);
        memcpy(bp, &indx, sizeof(indx));
        bp += sizeof(indx);
-#ifdef DEBUG
+#ifdef DIAGNOSTIC
        if ((u_int32_t)(bp - (u_int8_t *)logrec.data) != logrec.size)
                fprintf(stderr, "Error in log record length");
 #endif
@@ -1140,22 +1144,23 @@ int __bam_cdel_log(logp, txnid, ret_lsnp, flags,
  * PUBLIC:    __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
  */
 int
-__bam_cdel_print(notused1, dbtp, lsnp, notused3, notused4)
+__bam_cdel_print(notused1, dbtp, lsnp, notused2, notused3)
        DB_LOG *notused1;
        DBT *dbtp;
        DB_LSN *lsnp;
-       int notused3;
-       void *notused4;
+       int notused2;
+       void *notused3;
 {
        __bam_cdel_args *argp;
        u_int32_t i;
-       int c, ret;
+       u_int ch;
+       int ret;
 
        i = 0;
-       c = 0;
+       ch = 0;
        notused1 = NULL;
-       notused3 = 0;
-       notused4 = NULL;
+       notused2 = 0;
+       notused3 = NULL;
 
        if ((ret = __bam_cdel_read(dbtp->data, &argp)) != 0)
                return (ret);
@@ -1307,7 +1312,7 @@ int __bam_repl_log(logp, txnid, ret_lsnp, flags,
        bp += sizeof(prefix);
        memcpy(bp, &suffix, sizeof(suffix));
        bp += sizeof(suffix);
-#ifdef DEBUG
+#ifdef DIAGNOSTIC
        if ((u_int32_t)(bp - (u_int8_t *)logrec.data) != logrec.size)
                fprintf(stderr, "Error in log record length");
 #endif
@@ -1323,22 +1328,23 @@ int __bam_repl_log(logp, txnid, ret_lsnp, flags,
  * PUBLIC:    __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
  */
 int
-__bam_repl_print(notused1, dbtp, lsnp, notused3, notused4)
+__bam_repl_print(notused1, dbtp, lsnp, notused2, notused3)
        DB_LOG *notused1;
        DBT *dbtp;
        DB_LSN *lsnp;
-       int notused3;
-       void *notused4;
+       int notused2;
+       void *notused3;
 {
        __bam_repl_args *argp;
        u_int32_t i;
-       int c, ret;
+       u_int ch;
+       int ret;
 
        i = 0;
-       c = 0;
+       ch = 0;
        notused1 = NULL;
-       notused3 = 0;
-       notused4 = NULL;
+       notused2 = 0;
+       notused3 = NULL;
 
        if ((ret = __bam_repl_read(dbtp->data, &argp)) != 0)
                return (ret);
@@ -1357,20 +1363,20 @@ __bam_repl_print(notused1, dbtp, lsnp, notused3, notused4)
        printf("\tisdeleted: %lu\n", (u_long)argp->isdeleted);
        printf("\torig: ");
        for (i = 0; i < argp->orig.size; i++) {
-               c = ((char *)argp->orig.data)[i];
-               if (isprint(c) || c == 0xa)
-                       putchar(c);
+               ch = ((u_int8_t *)argp->orig.data)[i];
+               if (isprint(ch) || ch == 0xa)
+                       putchar(ch);
                else
-                       printf("%#x ", c);
+                       printf("%#x ", ch);
        }
        printf("\n");
        printf("\trepl: ");
        for (i = 0; i < argp->repl.size; i++) {
-               c = ((char *)argp->repl.data)[i];
-               if (isprint(c) || c == 0xa)
-                       putchar(c);
+               ch = ((u_int8_t *)argp->repl.data)[i];
+               if (isprint(ch) || ch == 0xa)
+                       putchar(ch);
                else
-                       printf("%#x ", c);
+                       printf("%#x ", ch);
        }
        printf("\n");
        printf("\tprefix: %lu\n", (u_long)argp->prefix);
index 85f4e8c..4e144b1 100644 (file)
@@ -1,14 +1,14 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 1996, 1997
+ * Copyright (c) 1996, 1997, 1998
  *     Sleepycat Software.  All rights reserved.
  */
 
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)getlong.c    10.2 (Sleepycat) 5/1/97";
+static const char sccsid[] = "@(#)getlong.c    10.3 (Sleepycat) 4/10/98";
 #endif /* not lint */
 
 #ifndef NO_SYSTEM_INCLUDES
index 4ee9e4f..6ec007b 100644 (file)
@@ -1,23 +1,21 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 1996, 1997
+ * Copyright (c) 1996, 1997, 1998
  *     Sleepycat Software.  All rights reserved.
  */
 
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)db_appinit.c 10.38 (Sleepycat) 1/7/98";
+static const char sccsid[] = "@(#)db_appinit.c 10.52 (Sleepycat) 6/2/98";
 #endif /* not lint */
 
 #ifndef NO_SYSTEM_INCLUDES
-#include <sys/param.h>
-#include <sys/stat.h>
+#include <sys/types.h>
 
 #include <ctype.h>
 #include <errno.h>
-#include <fcntl.h>
 #include <signal.h>
 #include <stdlib.h>
 #include <string.h>
@@ -34,14 +32,14 @@ static const char sccsid[] = "@(#)db_appinit.c      10.38 (Sleepycat) 1/7/98";
 #include "clib_ext.h"
 #include "common_ext.h"
 
-static int __db_home __P((DB_ENV *, const char *, int));
+static int __db_home __P((DB_ENV *, const char *, u_int32_t));
 static int __db_parse __P((DB_ENV *, char *));
-static int __db_tmp_dir __P((DB_ENV *, int));
-static int __db_tmp_open __P((DB_ENV *, char *, int *));
+static int __db_tmp_dir __P((DB_ENV *, u_int32_t));
+static int __db_tmp_open __P((DB_ENV *, u_int32_t, char *, int *));
 
 /*
  * db_version --
- *     Return verision information.
+ *     Return version information.
  */
 char *
 db_version(majverp, minverp, patchp)
@@ -65,16 +63,18 @@ db_appinit(db_home, db_config, dbenv, flags)
        const char *db_home;
        char * const *db_config;
        DB_ENV *dbenv;
-       int flags;
+       u_int32_t flags;
 {
        FILE *fp;
-       int ret;
+       int mode, ret;
        char * const *p;
        char *lp, buf[MAXPATHLEN * 2];
 
        /* Validate arguments. */
        if (dbenv == NULL)
                return (EINVAL);
+
+
 #ifdef HAVE_SPINLOCKS
 #define        OKFLAGS                                                         \
    (DB_CREATE | DB_NOMMAP | DB_THREAD | DB_INIT_LOCK | DB_INIT_LOG |   \
@@ -89,10 +89,9 @@ db_appinit(db_home, db_config, dbenv, flags)
        if ((ret = __db_fchk(dbenv, "db_appinit", flags, OKFLAGS)) != 0)
                return (ret);
 
-#define        RECOVERY_FLAGS (DB_CREATE | DB_INIT_TXN | DB_INIT_LOG)
-       if (LF_ISSET(DB_RECOVER | DB_RECOVER_FATAL) &&
-           LF_ISSET(RECOVERY_FLAGS) != RECOVERY_FLAGS)
-               return (__db_ferr(dbenv, "db_appinit", 1));
+       /* Transactions imply logging. */
+       if (LF_ISSET(DB_INIT_TXN))
+               LF_SET(DB_INIT_LOG);
 
        /* Convert the db_appinit(3) flags. */
        if (LF_ISSET(DB_THREAD))
@@ -147,47 +146,48 @@ db_appinit(db_home, db_config, dbenv, flags)
        F_SET(dbenv, DB_ENV_APPINIT);
 
        /*
-        * If we are doing recovery, remove all the regions.
+        * If we are doing recovery, remove all the old shared memory
+        * regions.
         */
        if (LF_ISSET(DB_RECOVER | DB_RECOVER_FATAL)) {
-               /* Remove all the old shared memory regions.  */
-               if ((ret = log_unlink(NULL, 1 /* force */, dbenv)) != 0)
+               if ((ret = log_unlink(NULL, 1, dbenv)) != 0)
                        goto err;
-               if ((ret = memp_unlink(NULL, 1 /* force */, dbenv)) != 0)
+               if ((ret = memp_unlink(NULL, 1, dbenv)) != 0)
                        goto err;
-               if ((ret = lock_unlink(NULL, 1 /* force */, dbenv)) != 0)
+               if ((ret = lock_unlink(NULL, 1, dbenv)) != 0)
                        goto err;
-               if ((ret = txn_unlink(NULL, 1 /* force */, dbenv)) != 0)
+               if ((ret = txn_unlink(NULL, 1, dbenv)) != 0)
                        goto err;
        }
 
-       /* Transactions imply logging. */
-       if (LF_ISSET(DB_INIT_TXN))
-               LF_SET(DB_INIT_LOG);
-
-       /* Default permissions are 0660. */
-#undef DB_DEFPERM
-#define        DB_DEFPERM      (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)
-
-       /* Initialize the subsystems. */
+       /*
+        * Create the new shared regions.
+        *
+        * Default permissions are read-write for both owner and group.
+        */
+       mode = __db_omode("rwrw--");
        if (LF_ISSET(DB_INIT_LOCK) && (ret = lock_open(NULL,
            LF_ISSET(DB_CREATE | DB_THREAD),
-           DB_DEFPERM, dbenv, &dbenv->lk_info)) != 0)
+           mode, dbenv, &dbenv->lk_info)) != 0)
                goto err;
        if (LF_ISSET(DB_INIT_LOG) && (ret = log_open(NULL,
            LF_ISSET(DB_CREATE | DB_THREAD),
-           DB_DEFPERM, dbenv, &dbenv->lg_info)) != 0)
+           mode, dbenv, &dbenv->lg_info)) != 0)
                goto err;
        if (LF_ISSET(DB_INIT_MPOOL) && (ret = memp_open(NULL,
            LF_ISSET(DB_CREATE | DB_MPOOL_PRIVATE | DB_NOMMAP | DB_THREAD),
-           DB_DEFPERM, dbenv, &dbenv->mp_info)) != 0)
+           mode, dbenv, &dbenv->mp_info)) != 0)
                goto err;
        if (LF_ISSET(DB_INIT_TXN) && (ret = txn_open(NULL,
            LF_ISSET(DB_CREATE | DB_THREAD | DB_TXN_NOSYNC),
-           DB_DEFPERM, dbenv, &dbenv->tx_info)) != 0)
+           mode, dbenv, &dbenv->tx_info)) != 0)
                goto err;
 
-       /* Initialize recovery. */
+       /*
+        * If the application is running with transactions, initialize the
+        * function tables.  Once that's done, do recovery for any previous
+        * run.
+        */
        if (LF_ISSET(DB_INIT_TXN)) {
                if ((ret = __bam_init_recover(dbenv)) != 0)
                        goto err;
@@ -199,12 +199,12 @@ db_appinit(db_home, db_config, dbenv, flags)
                        goto err;
                if ((ret = __txn_init_recover(dbenv)) != 0)
                        goto err;
-       }
 
-       /* Run recovery if necessary. */
-       if (LF_ISSET(DB_RECOVER | DB_RECOVER_FATAL) && (ret =
-           __db_apprec(dbenv, LF_ISSET(DB_RECOVER | DB_RECOVER_FATAL))) != 0)
-               goto err;
+               if (LF_ISSET(DB_RECOVER | DB_RECOVER_FATAL) &&
+                   (ret = __db_apprec(dbenv,
+                   LF_ISSET(DB_RECOVER | DB_RECOVER_FATAL))) != 0)
+                       goto err;
+       }
 
        return (ret);
 
@@ -282,21 +282,21 @@ db_appexit(dbenv)
  *     it in allocated space.
  *
  * PUBLIC: int __db_appname __P((DB_ENV *,
- * PUBLIC:    APPNAME, const char *, const char *, int *, char **));
+ * PUBLIC:    APPNAME, const char *, const char *, u_int32_t, int *, char **));
  */
 int
-__db_appname(dbenv, appname, dir, file, fdp, namep)
+__db_appname(dbenv, appname, dir, file, tmp_oflags, fdp, namep)
        DB_ENV *dbenv;
        APPNAME appname;
        const char *dir, *file;
+       u_int32_t tmp_oflags;
        int *fdp;
        char **namep;
 {
        DB_ENV etmp;
        size_t len;
-       int ret, slash, tmp_create, tmp_free;
+       int data_entry, ret, slash, tmp_create, tmp_free;
        const char *a, *b, *c;
-       int data_entry;
        char *p, *start;
 
        a = b = c = NULL;
@@ -349,8 +349,8 @@ __db_appname(dbenv, appname, dir, file, fdp, namep)
         *
         * DB_ENV          APPNAME         RESULT
         * -------------------------------------------
-        * null            DB_APP_TMP      <tmp>/<create>
-        * set             DB_APP_TMP      DB_HOME/DB_TMP_DIR/<create>
+        * null            DB_APP_TMP*     <tmp>/<create>
+        * set             DB_APP_TMP*     DB_HOME/DB_TMP_DIR/<create>
         */
 retry: switch (appname) {
        case DB_APP_NONE:
@@ -431,7 +431,14 @@ done:      len =
            (c == NULL ? 0 : strlen(c) + 1) +
            (file == NULL ? 0 : strlen(file) + 1);
 
-       if ((start = (char *)__db_malloc(len)) == NULL) {
+       /*
+        * Allocate space to hold the current path information, as well as any
+        * temporary space that we're going to need to create a temporary file
+        * name.
+        */
+#define        DB_TRAIL        "XXXXXX"
+       if ((start =
+           (char *)__db_malloc(len + sizeof(DB_TRAIL) + 10)) == NULL) {
                __db_err(dbenv, "%s", strerror(ENOMEM));
                if (tmp_free)
                        FREES(etmp.db_tmp_dir);
@@ -460,14 +467,15 @@ done:     len =
                FREES(etmp.db_tmp_dir);
 
        /* Create the file if so requested. */
-       if (tmp_create) {
-               ret = __db_tmp_open(dbenv, start, fdp);
+       if (tmp_create &&
+           (ret = __db_tmp_open(dbenv, tmp_oflags, start, fdp)) != 0) {
                FREES(start);
-       } else {
-               *namep = start;
-               ret = 0;
+               return (ret);
        }
-       return (ret);
+
+       if (namep != NULL)
+               *namep = start;
+       return (0);
 }
 
 /*
@@ -478,7 +486,7 @@ static int
 __db_home(dbenv, db_home, flags)
        DB_ENV *dbenv;
        const char *db_home;
-       int flags;
+       u_int32_t flags;
 {
        const char *p;
 
@@ -532,10 +540,12 @@ __db_parse(dbenv, s)
                return (ENOMEM);
 
        tp = local_s;
-       while ((name = strsep(&tp, " \t")) != NULL && *name == '\0');
+       while ((name = strsep(&tp, " \t")) != NULL && *name == '\0')
+               ;
        if (name == NULL)
                goto illegal;
-       while ((value = strsep(&tp, " \t")) != NULL && *value == '\0');
+       while ((value = strsep(&tp, " \t")) != NULL && *value == '\0')
+               ;
        if (value == NULL) {
 illegal:       ret = EINVAL;
                __db_err(dbenv, "illegal name-value pair: %s", s);
@@ -591,7 +601,7 @@ static char *sTempFolder;
 static int
 __db_tmp_dir(dbenv, flags)
        DB_ENV *dbenv;
-       int flags;
+       u_int32_t flags;
 {
        static const char * list[] = {  /* Ordered: see db_appinit(3). */
                "/var/tmp",
@@ -671,49 +681,45 @@ __db_tmp_dir(dbenv, flags)
  *     Create a temporary file.
  */
 static int
-__db_tmp_open(dbenv, dir, fdp)
+__db_tmp_open(dbenv, flags, path, fdp)
        DB_ENV *dbenv;
-       char *dir;
+       u_int32_t flags;
+       char *path;
        int *fdp;
 {
 #ifdef HAVE_SIGFILLSET
        sigset_t set, oset;
 #endif
        u_long pid;
-       size_t len;
-       int isdir, ret;
-       char *trv, buf[MAXPATHLEN];
+       int mode, isdir, ret;
+       const char *p;
+       char *trv;
 
        /*
         * Check the target directory; if you have six X's and it doesn't
         * exist, this runs for a *very* long time.
         */
-       if ((ret = __db_exists(dir, &isdir)) != 0) {
-               __db_err(dbenv, "%s: %s", dir, strerror(ret));
+       if ((ret = __db_exists(path, &isdir)) != 0) {
+               __db_err(dbenv, "%s: %s", path, strerror(ret));
                return (ret);
        }
        if (!isdir) {
-               __db_err(dbenv, "%s: %s", dir, strerror(EINVAL));
+               __db_err(dbenv, "%s: %s", path, strerror(EINVAL));
                return (EINVAL);
        }
 
        /* Build the path. */
-#define        DB_TRAIL        "/XXXXXX"
-       if ((len = strlen(dir)) + sizeof(DB_TRAIL) > sizeof(buf)) {
-               __db_err(dbenv,
-                   "tmp_open: %s: %s", buf, strerror(ENAMETOOLONG));
-               return (ENAMETOOLONG);
-       }
-       (void)strcpy(buf, dir);
-       (void)strcpy(buf + len, DB_TRAIL);
-       buf[len] = PATH_SEPARATOR[0];                   /* WIN32 */
+       for (trv = path; *trv != '\0'; ++trv)
+               ;
+       *trv = PATH_SEPARATOR[0];
+       for (p = DB_TRAIL; (*++trv = *p) != '\0'; ++p)
+               ;
 
        /*
         * Replace the X's with the process ID.  Pid should be a pid_t,
         * but we use unsigned long for portability.
         */
-       for (pid = getpid(),
-           trv = buf + len + sizeof(DB_TRAIL) - 1; *--trv == 'X'; pid /= 10)
+       for (pid = getpid(); *--trv == 'X'; pid /= 10)
                switch (pid % 10) {
                case 0: *trv = '0'; break;
                case 1: *trv = '1'; break;
@@ -728,30 +734,33 @@ __db_tmp_open(dbenv, dir, fdp)
                }
        ++trv;
 
+       /* Set up open flags and mode. */
+       LF_SET(DB_CREATE | DB_EXCL);
+       mode = __db_omode("rw----");
+
        /*
-        * Try and open a file.  We block every signal we can get our hands
+        * Try to open a file.  We block every signal we can get our hands
         * on so that, if we're interrupted at the wrong time, the temporary
         * file isn't left around -- of course, if we drop core in-between
         * the calls we'll hang forever, but that's probably okay.  ;-}
         */
 #ifdef HAVE_SIGFILLSET
-       (void)sigfillset(&set);
+       if (LF_ISSET(DB_TEMPORARY))
+               (void)sigfillset(&set);
 #endif
        for (;;) {
 #ifdef HAVE_SIGFILLSET
-               (void)sigprocmask(SIG_BLOCK, &set, &oset);
+               if (LF_ISSET(DB_TEMPORARY))
+                       (void)sigprocmask(SIG_BLOCK, &set, &oset);
 #endif
-#define        DB_TEMPOPEN     DB_CREATE | DB_EXCL | DB_TEMPORARY
-               if ((ret = __db_open(buf,
-                   DB_TEMPOPEN, DB_TEMPOPEN, S_IRUSR | S_IWUSR, fdp)) == 0) {
+               ret = __db_open(path, flags, flags, mode, fdp);
 #ifdef HAVE_SIGFILLSET
+               if (LF_ISSET(DB_TEMPORARY))
                        (void)sigprocmask(SIG_SETMASK, &oset, NULL);
 #endif
+               if (ret == 0)
                        return (0);
-               }
-#ifdef HAVE_SIGFILLSET
-               (void)sigprocmask(SIG_SETMASK, &oset, NULL);
-#endif
+
                /*
                 * XXX:
                 * If we don't get an EEXIST error, then there's something
@@ -761,7 +770,7 @@ __db_tmp_open(dbenv, dir, fdp)
                 */
                if (ret != EEXIST) {
                        __db_err(dbenv,
-                           "tmp_open: %s: %s", buf, strerror(ret));
+                           "tmp_open: %s: %s", path, strerror(ret));
                        return (ret);
                }
 
index 7a42e13..df707ea 100644 (file)
@@ -1,7 +1,7 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 1996, 1997
+ * Copyright (c) 1996, 1997, 1998
  *     Sleepycat Software.  All rights reserved.
  */
 
@@ -9,18 +9,17 @@
 
 #ifndef lint
 static const char copyright[] =
-"@(#) Copyright (c) 1997\n\
+"@(#) Copyright (c) 1996, 1997, 1998\n\
        Sleepycat Software Inc.  All rights reserved.\n";
-static const char sccsid[] = "@(#)db_apprec.c  10.23 (Sleepycat) 1/17/98";
+static const char sccsid[] = "@(#)db_apprec.c  10.30 (Sleepycat) 5/3/98";
 #endif
 
 #ifndef NO_SYSTEM_INCLUDES
 #include <sys/types.h>
 
 #include <errno.h>
-#include <time.h>
 #include <string.h>
-#include <stdlib.h>
+#include <time.h>
 #endif
 
 #include "db_int.h"
@@ -36,18 +35,19 @@ static const char sccsid[] = "@(#)db_apprec.c       10.23 (Sleepycat) 1/17/98";
  * __db_apprec --
  *     Perform recovery.
  *
- * PUBLIC: int __db_apprec __P((DB_ENV *, int));
+ * PUBLIC: int __db_apprec __P((DB_ENV *, u_int32_t));
  */
 int
 __db_apprec(dbenv, flags)
        DB_ENV *dbenv;
-       int flags;
+       u_int32_t flags;
 {
        DBT data;
        DB_LOG *lp;
        DB_LSN ckp_lsn, first_lsn, lsn;
        time_t now;
-       int is_thread, ret;
+       u_int32_t is_thread;
+       int ret;
        void *txninfo;
 
        lp = dbenv->lg_info;
@@ -91,14 +91,14 @@ __db_apprec(dbenv, flags)
        if ((ret = log_get(lp, &ckp_lsn, &data, DB_CHECKPOINT)) != 0) {
                /*
                 * If we don't find a checkpoint, start from the beginning.
-                * If that fails, we're done.  Note, we require that there
-                * be log records if we're performing recovery, and fail if
-                * there aren't.
+                * If that fails, we're done.  Note, we do not require that
+                * there be log records if we're performing recovery.
                 */
                if ((ret = log_get(lp, &ckp_lsn, &data, DB_FIRST)) != 0) {
-                       __db_err(dbenv, "First log record not found");
                        if (ret == DB_NOTFOUND)
-                               ret = EINVAL;
+                               ret = 0;
+                       else
+                               __db_err(dbenv, "First log record not found");
                        goto out;
                }
        }
@@ -134,14 +134,17 @@ __db_apprec(dbenv, flags)
        } else
                if ((ret = __log_findckp(lp, &first_lsn)) == DB_NOTFOUND) {
                        /*
-                        * If recovery was specified, there must be log files.
-                        * If we don't find one, it's an error.  (This should
-                        * have been caught above, when a log_get() of DB_FIRST
-                        * or DB_CHECKPOINT succeeded, but paranoia is good.)
+                        * We don't require that log files exist if recovery
+                        * was specified.
                         */
-                       ret = EINVAL;
+                       ret = 0;
                        goto out;
                }
+
+       if (dbenv->db_verbose)
+               __db_err(lp->dbenv, "Recovery starting from [%lu][%lu]",
+                   (u_long)first_lsn.file, (u_long)first_lsn.offset);
+
        for (ret = log_get(lp, &lsn, &data, DB_LAST);
            ret == 0 && log_compare(&lsn, &first_lsn) > 0;
            ret = log_get(lp, &lsn, &data, DB_PREV)) {
@@ -175,21 +178,21 @@ __db_apprec(dbenv, flags)
        __log_close_files(lp);
 
        /*
-        * Now set the maximum transaction id, set the last checkpoint lsn,
-        * and the current time.  Then take a checkpoint.
+        * Now set the last checkpoint lsn and the current time,
+        * take a checkpoint, and reset the txnid.
         */
        (void)time(&now);
-       dbenv->tx_info->region->last_txnid = ((__db_txnhead *)txninfo)->maxid;
        dbenv->tx_info->region->last_ckp = ckp_lsn;
        dbenv->tx_info->region->time_ckp = (u_int32_t)now;
        if ((ret = txn_checkpoint(dbenv->tx_info, 0, 0)) != 0)
                goto out;
+       dbenv->tx_info->region->last_txnid = TXN_MINIMUM;
 
        if (dbenv->db_verbose) {
                __db_err(lp->dbenv, "Recovery complete at %.24s", ctime(&now));
-               __db_err(lp->dbenv, "%s %lu %s [%lu][%lu]",
+               __db_err(lp->dbenv, "%s %lx %s [%lu][%lu]",
                    "Maximum transaction id",
-                   (u_long)dbenv->tx_info->region->last_txnid,
+                   ((DB_TXNHEAD *)txninfo)->maxid,
                    "Recovery checkpoint",
                    (u_long)dbenv->tx_info->region->last_ckp.file,
                    (u_long)dbenv->tx_info->region->last_ckp.offset);
index e486132..cadf742 100644 (file)
@@ -1,14 +1,14 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 1996, 1997
+ * Copyright (c) 1996, 1997, 1998
  *     Sleepycat Software.  All rights reserved.
  */
 
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)db_byteorder.c       10.4 (Sleepycat) 9/4/97";
+static const char sccsid[] = "@(#)db_byteorder.c       10.5 (Sleepycat) 4/10/98";
 #endif /* not lint */
 
 #ifndef NO_SYSTEM_INCLUDES
index fc59aad..98a4142 100644 (file)
@@ -1,14 +1,14 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 1996, 1997
+ * Copyright (c) 1996, 1997, 1998
  *     Sleepycat Software.  All rights reserved.
  */
 
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)db_err.c     10.21 (Sleepycat) 1/13/98";
+static const char sccsid[] = "@(#)db_err.c     10.25 (Sleepycat) 5/2/98";
 #endif /* not lint */
 
 #ifndef NO_SYSTEM_INCLUDES
@@ -26,6 +26,7 @@ static const char sccsid[] = "@(#)db_err.c    10.21 (Sleepycat) 1/13/98";
 #include "db_int.h"
 #include "common_ext.h"
 
+static int __db_keyempty __P((const DB_ENV *));
 static int __db_rdonly __P((const DB_ENV *, const char *));
 
 /*
@@ -81,11 +82,11 @@ __db_err(dbenv, fmt, va_alist)
  * appears before the assignment in the __db__panic() call.
  */
 static int __db_ecursor __P((DB *, DB_TXN *, DBC **));
-static int __db_edel __P((DB *, DB_TXN *, DBT *, int));
+static int __db_edel __P((DB *, DB_TXN *, DBT *, u_int32_t));
 static int __db_efd __P((DB *, int *));
-static int __db_egp __P((DB *, DB_TXN *, DBT *, DBT *, int));
-static int __db_estat __P((DB *, void *, void *(*)(size_t), int));
-static int __db_esync __P((DB *, int));
+static int __db_egp __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t));
+static int __db_estat __P((DB *, void *, void *(*)(size_t), u_int32_t));
+static int __db_esync __P((DB *, u_int32_t));
 
 /*
  * __db_ecursor --
@@ -113,7 +114,7 @@ __db_edel(a, b, c, d)
        DB *a;
        DB_TXN *b;
        DBT *c;
-       int d;
+       u_int32_t d;
 {
        COMPQUIET(a, NULL);
        COMPQUIET(b, NULL);
@@ -147,7 +148,7 @@ __db_egp(a, b, c, d, e)
        DB *a;
        DB_TXN *b;
        DBT *c, *d;
-       int e;
+       u_int32_t e;
 {
        COMPQUIET(a, NULL);
        COMPQUIET(b, NULL);
@@ -167,7 +168,7 @@ __db_estat(a, b, c, d)
        DB *a;
        void *b;
        void *(*c) __P((size_t));
-       int d;
+       u_int32_t d;
 {
        COMPQUIET(a, NULL);
        COMPQUIET(b, NULL);
@@ -184,7 +185,7 @@ __db_estat(a, b, c, d)
 static int
 __db_esync(a, b)
        DB *a;
-       int b;
+       u_int32_t b;
 {
        COMPQUIET(a, NULL);
        COMPQUIET(b, 0);
@@ -208,6 +209,10 @@ __db_panic(dbp)
         *
         * We should call mpool and have it shut down the file, so we get
         * other processes sharing this file as well.
+        *
+        *      Chaos reigns within.
+        *      Reflect, repent, and reboot.
+        *      Order shall return.
         */
        dbp->cursor = __db_ecursor;
        dbp->del = __db_edel;
@@ -235,13 +240,13 @@ __db_panic(dbp)
  * __db_fchk --
  *     General flags checking routine.
  *
- * PUBLIC: int __db_fchk __P((DB_ENV *, const char *, int, int));
+ * PUBLIC: int __db_fchk __P((DB_ENV *, const char *, u_int32_t, u_int32_t));
  */
 int
 __db_fchk(dbenv, name, flags, ok_flags)
        DB_ENV *dbenv;
        const char *name;
-       int flags, ok_flags;
+       u_int32_t flags, ok_flags;
 {
        DB_CHECK_FLAGS(dbenv, name, flags, ok_flags);
        return (0);
@@ -251,13 +256,14 @@ __db_fchk(dbenv, name, flags, ok_flags)
  * __db_fcchk --
  *     General combination flags checking routine.
  *
- * PUBLIC: int __db_fcchk __P((DB_ENV *, const char *, int, int, int));
+ * PUBLIC: int __db_fcchk
+ * PUBLIC:    __P((DB_ENV *, const char *, u_int32_t, u_int32_t, u_int32_t));
  */
 int
 __db_fcchk(dbenv, name, flags, flag1, flag2)
        DB_ENV *dbenv;
        const char *name;
-       int flags, flag1, flag2;
+       u_int32_t flags, flag1, flag2;
 {
        DB_CHECK_FCOMBO(dbenv, name, flags, flag1, flag2);
        return (0);
@@ -267,12 +273,13 @@ __db_fcchk(dbenv, name, flags, flag1, flag2)
  * __db_cdelchk --
  *     Common cursor delete argument checking routine.
  *
- * PUBLIC: int __db_cdelchk __P((const DB *, int, int, int));
+ * PUBLIC: int __db_cdelchk __P((const DB *, u_int32_t, int, int));
  */
 int
 __db_cdelchk(dbp, flags, isrdonly, isvalid)
        const DB *dbp;
-       int flags, isrdonly, isvalid;
+       u_int32_t flags;
+       int isrdonly, isvalid;
 {
        /* Check for changes to a read-only tree. */
        if (isrdonly)
@@ -292,17 +299,18 @@ __db_cdelchk(dbp, flags, isrdonly, isvalid)
  * __db_cgetchk --
  *     Common cursor get argument checking routine.
  *
- * PUBLIC: int __db_cgetchk __P((const DB *, DBT *, DBT *, int, int));
+ * PUBLIC: int __db_cgetchk __P((const DB *, DBT *, DBT *, u_int32_t, int));
  */
 int
 __db_cgetchk(dbp, key, data, flags, isvalid)
        const DB *dbp;
        DBT *key, *data;
-       int flags, isvalid;
+       u_int32_t flags;
+       int isvalid;
 {
-       int check_key;
+       int key_einval, key_flags;
 
-       check_key = 0;
+       key_flags = key_einval = 0;
 
        /* Check for invalid dbc->c_get() function flags. */
        switch (flags) {
@@ -311,10 +319,13 @@ __db_cgetchk(dbp, key, data, flags, isvalid)
        case DB_LAST:
        case DB_NEXT:
        case DB_PREV:
+               key_flags = 1;
+               break;
        case DB_SET_RANGE:
-               check_key = 1;
+               key_einval = key_flags = 1;
                break;
        case DB_SET:
+               key_einval = 1;
                break;
        case DB_GET_RECNO:
                if (!F_ISSET(dbp, DB_BT_RECNUM))
@@ -323,14 +334,14 @@ __db_cgetchk(dbp, key, data, flags, isvalid)
        case DB_SET_RECNO:
                if (!F_ISSET(dbp, DB_BT_RECNUM))
                        goto err;
-               check_key = 1;
+               key_einval = key_flags = 1;
                break;
        default:
 err:           return (__db_ferr(dbp->dbenv, "c_get", 0));
        }
 
        /* Check for invalid key/data flags. */
-       if (check_key)
+       if (key_flags)
                DB_CHECK_FLAGS(dbp->dbenv, "key", key->flags,
                    DB_DBT_MALLOC | DB_DBT_USERMEM | DB_DBT_PARTIAL);
        DB_CHECK_FLAGS(dbp->dbenv, "data", data->flags,
@@ -340,11 +351,15 @@ err:              return (__db_ferr(dbp->dbenv, "c_get", 0));
        if (F_ISSET(dbp, DB_AM_THREAD)) {
                if (!F_ISSET(data, DB_DBT_USERMEM | DB_DBT_MALLOC))
                        return (__db_ferr(dbp->dbenv, "threaded data", 1));
-               if (check_key &&
+               if (key_flags &&
                    !F_ISSET(key, DB_DBT_USERMEM | DB_DBT_MALLOC))
                        return (__db_ferr(dbp->dbenv, "threaded key", 1));
        }
 
+       /* Check for missing keys. */
+       if (key_einval && (key->data == NULL || key->size == 0))
+               return (__db_keyempty(dbp->dbenv));
+
        /*
         * The cursor must be initialized for DB_CURRENT, return -1 for an
         * invalid cursor, otherwise 0.
@@ -357,23 +372,24 @@ err:              return (__db_ferr(dbp->dbenv, "c_get", 0));
  *     Common cursor put argument checking routine.
  *
  * PUBLIC: int __db_cputchk __P((const DB *,
- * PUBLIC:    const DBT *, DBT *, int, int, int));
+ * PUBLIC:    const DBT *, DBT *, u_int32_t, int, int));
  */
 int
 __db_cputchk(dbp, key, data, flags, isrdonly, isvalid)
        const DB *dbp;
        const DBT *key;
        DBT *data;
-       int flags, isrdonly, isvalid;
+       u_int32_t flags;
+       int isrdonly, isvalid;
 {
-       int check_key;
+       int key_einval, key_flags;
 
        /* Check for changes to a read-only tree. */
        if (isrdonly)
                return (__db_rdonly(dbp->dbenv, "c_put"));
 
        /* Check for invalid dbc->c_put() function flags. */
-       check_key = 0;
+       key_einval = key_flags = 0;
        switch (flags) {
        case DB_AFTER:
        case DB_BEFORE:
@@ -388,19 +404,23 @@ __db_cputchk(dbp, key, data, flags, isrdonly, isvalid)
        case DB_KEYLAST:
                if (dbp->type == DB_RECNO)
                        goto err;
-               check_key = 1;
+               key_einval = key_flags = 1;
                break;
        default:
 err:           return (__db_ferr(dbp->dbenv, "c_put", 0));
        }
 
        /* Check for invalid key/data flags. */
-       if (check_key)
+       if (key_flags)
                DB_CHECK_FLAGS(dbp->dbenv, "key", key->flags,
                    DB_DBT_MALLOC | DB_DBT_USERMEM | DB_DBT_PARTIAL);
        DB_CHECK_FLAGS(dbp->dbenv, "data", data->flags,
            DB_DBT_MALLOC | DB_DBT_USERMEM | DB_DBT_PARTIAL);
 
+       /* Check for missing keys. */
+       if (key_einval && (key->data == NULL || key->size == 0))
+               return (__db_keyempty(dbp->dbenv));
+
        /*
         * The cursor must be initialized for anything other than DB_KEYFIRST
         * and DB_KEYLAST, return -1 for an invalid cursor, otherwise 0.
@@ -413,12 +433,14 @@ err:              return (__db_ferr(dbp->dbenv, "c_put", 0));
  * __db_delchk --
  *     Common delete argument checking routine.
  *
- * PUBLIC: int __db_delchk __P((const DB *, int, int));
+ * PUBLIC: int __db_delchk __P((const DB *, DBT *, u_int32_t, int));
  */
 int
-__db_delchk(dbp, flags, isrdonly)
+__db_delchk(dbp, key, flags, isrdonly)
        const DB *dbp;
-       int flags, isrdonly;
+       DBT *key;
+       u_int32_t flags;
+       int isrdonly;
 {
        /* Check for changes to a read-only tree. */
        if (isrdonly)
@@ -427,6 +449,10 @@ __db_delchk(dbp, flags, isrdonly)
        /* Check for invalid db->del() function flags. */
        DB_CHECK_FLAGS(dbp->dbenv, "delete", flags, 0);
 
+       /* Check for missing keys. */
+       if (key->data == NULL || key->size == 0)
+               return (__db_keyempty(dbp->dbenv));
+
        return (0);
 }
 
@@ -434,14 +460,14 @@ __db_delchk(dbp, flags, isrdonly)
  * __db_getchk --
  *     Common get argument checking routine.
  *
- * PUBLIC: int __db_getchk __P((const DB *, const DBT *, DBT *, int));
+ * PUBLIC: int __db_getchk __P((const DB *, const DBT *, DBT *, u_int32_t));
  */
 int
 __db_getchk(dbp, key, data, flags)
        const DB *dbp;
        const DBT *key;
        DBT *data;
-       int flags;
+       u_int32_t flags;
 {
        /* Check for invalid db->get() function flags. */
        DB_CHECK_FLAGS(dbp->dbenv,
@@ -457,6 +483,10 @@ __db_getchk(dbp, key, data, flags)
            !F_ISSET(data, DB_DBT_MALLOC | DB_DBT_USERMEM))
                return (__db_ferr(dbp->dbenv, "threaded data", 1));
 
+       /* Check for missing keys. */
+       if (key->data == NULL || key->size == 0)
+               return (__db_keyempty(dbp->dbenv));
+
        return (0);
 }
 
@@ -464,14 +494,16 @@ __db_getchk(dbp, key, data, flags)
  * __db_putchk --
  *     Common put argument checking routine.
  *
- * PUBLIC: int __db_putchk __P((const DB *, DBT *, const DBT *, int, int, int));
+ * PUBLIC: int __db_putchk
+ * PUBLIC:    __P((const DB *, DBT *, const DBT *, u_int32_t, int, int));
  */
 int
 __db_putchk(dbp, key, data, flags, isrdonly, isdup)
        const DB *dbp;
        DBT *key;
        const DBT *data;
-       int flags, isrdonly, isdup;
+       u_int32_t flags;
+       int isrdonly, isdup;
 {
        /* Check for changes to a read-only tree. */
        if (isrdonly)
@@ -488,12 +520,17 @@ __db_putchk(dbp, key, data, flags, isrdonly, isdup)
        DB_CHECK_FCOMBO(dbp->dbenv,
            "data", data->flags, DB_DBT_MALLOC, DB_DBT_USERMEM);
 
+       /* Check for missing keys. */
+       if (key->data == NULL || key->size == 0)
+               return (__db_keyempty(dbp->dbenv));
+
        /* Check for partial puts in the presence of duplicates. */
        if (isdup && F_ISSET(data, DB_DBT_PARTIAL)) {
                __db_err(dbp->dbenv,
 "a partial put in the presence of duplicates requires a cursor operation");
                return (EINVAL);
        }
+
        return (0);
 }
 
@@ -501,12 +538,12 @@ __db_putchk(dbp, key, data, flags, isrdonly, isdup)
  * __db_statchk --
  *     Common stat argument checking routine.
  *
- * PUBLIC: int __db_statchk __P((const DB *, int));
+ * PUBLIC: int __db_statchk __P((const DB *, u_int32_t));
  */
 int
 __db_statchk(dbp, flags)
        const DB *dbp;
-       int flags;
+       u_int32_t flags;
 {
        /* Check for invalid db->stat() function flags. */
        DB_CHECK_FLAGS(dbp->dbenv, "stat", flags, DB_RECORDCOUNT);
@@ -522,12 +559,12 @@ __db_statchk(dbp, flags)
  * __db_syncchk --
  *     Common sync argument checking routine.
  *
- * PUBLIC: int __db_syncchk __P((const DB *, int));
+ * PUBLIC: int __db_syncchk __P((const DB *, u_int32_t));
  */
 int
 __db_syncchk(dbp, flags)
        const DB *dbp;
-       int flags;
+       u_int32_t flags;
 {
        /* Check for invalid db->sync() function flags. */
        DB_CHECK_FLAGS(dbp->dbenv, "sync", flags, 0);
@@ -542,13 +579,13 @@ __db_syncchk(dbp, flags)
  * PUBLIC: int __db_ferr __P((const DB_ENV *, const char *, int));
  */
 int
-__db_ferr(dbenv, name, combo)
+__db_ferr(dbenv, name, iscombo)
        const DB_ENV *dbenv;
        const char *name;
-       int combo;
+       int iscombo;
 {
        __db_err(dbenv, "illegal flag %sspecified to %s",
-           combo ? "combination " : "", name);
+           iscombo ? "combination " : "", name);
        return (EINVAL);
 }
 
@@ -564,3 +601,15 @@ __db_rdonly(dbenv, name)
        __db_err(dbenv, "%s: attempt to modify a read-only tree", name);
        return (EACCES);
 }
+
+/*
+ * __db_keyempty --
+ *     Common missing or empty key value message.
+ */
+static int
+__db_keyempty(dbenv)
+       const DB_ENV *dbenv;
+{
+       __db_err(dbenv, "missing or empty key value specified");
+       return (EINVAL);
+}
index 9af0111..d6b14f5 100644 (file)
@@ -1,7 +1,7 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 1996, 1997
+ * Copyright (c) 1996, 1997, 1998
  *     Sleepycat Software.  All rights reserved.
  */
 /*
@@ -43,7 +43,7 @@
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)db_log2.c    10.3 (Sleepycat) 6/21/97";
+static const char sccsid[] = "@(#)db_log2.c    10.5 (Sleepycat) 4/26/98";
 #endif /* not lint */
 
 #ifndef NO_SYSTEM_INCLUDES
@@ -63,6 +63,7 @@ __db_log2(num)
        u_int32_t i, limit;
 
        limit = 1;
-       for (i = 0; limit < num; limit = limit << 1, i++);
+       for (i = 0; limit < num; limit = limit << 1, i++)
+               ;
        return (i);
 }
index 02d939e..6d15f7f 100644 (file)
@@ -1,59 +1,20 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 1996, 1997
+ * Copyright (c) 1996, 1997, 1998
  *     Sleepycat Software.  All rights reserved.
  */
-/*
- * Copyright (c) 1995, 1996
- *     The President and Fellows of Harvard University.  All rights reserved.
- *
- * This code is derived from software contributed to Harvard 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.
- */
 
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)db_region.c  10.21 (Sleepycat) 1/16/98";
+static const char sccsid[] = "@(#)db_region.c  10.46 (Sleepycat) 5/26/98";
 #endif /* not lint */
 
 #ifndef NO_SYSTEM_INCLUDES
 #include <sys/types.h>
-#include <sys/stat.h>
 
 #include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 #endif
@@ -61,548 +22,840 @@ static const char sccsid[] = "@(#)db_region.c     10.21 (Sleepycat) 1/16/98";
 #include "db_int.h"
 #include "common_ext.h"
 
-static int __db_rmap __P((DB_ENV *, int, size_t, void *));
+static int __db_growregion __P((REGINFO *, size_t));
 
 /*
- * __db_rcreate --
- *
- * Common interface for creating a shared region.  Handles synchronization
- * across multiple processes.
- *
- * The dbenv contains the environment for this process, including naming
- * information.  The path argument represents the parameters passed to
- * the open routines and may be either a file or a directory.  If it is
- * a directory, it must exist.  If it is a file, then the file parameter
- * must be NULL, otherwise, file is the name to be created inside the
- * directory path.
- *
- * The function returns a pointer to the shared region that has been mapped
- * into memory, NULL on error.
+ * __db_rattach --
+ *     Optionally create and attach to a shared memory region.
  *
- * PUBLIC: int __db_rcreate __P((DB_ENV *, APPNAME,
- * PUBLIC:    const char *, const char *, int, size_t, int, int *, void *));
+ * PUBLIC: int __db_rattach __P((REGINFO *));
  */
 int
-__db_rcreate(dbenv, appname, path, file, mode, size, oflags, fdp, retp)
-       DB_ENV *dbenv;
-       APPNAME appname;
-       const char *path, *file;
-       int mode, oflags, *fdp;
-       size_t size;
-       void *retp;
+__db_rattach(infop)
+       REGINFO *infop;
 {
-       RLAYOUT *rp;
-       int fd, ret;
-       char *name;
+       RLAYOUT *rlp, rl;
+       size_t grow_region, size;
+       ssize_t nr, nw;
+       u_int32_t flags, mbytes, bytes;
+       u_int8_t *p;
+       int malloc_possible, ret, retry_cnt;
+
+       grow_region = 0;
+       malloc_possible = 1;
+       ret = retry_cnt = 0;
+
+       /* Round off the requested size to the next page boundary. */
+       DB_ROUNDOFF(infop->size);
+
+       /* Some architectures have hard limits on the maximum region size. */
+#ifdef DB_REGIONSIZE_MAX
+       if (infop->size > DB_REGIONSIZE_MAX) {
+               __db_err(infop->dbenv, "__db_rattach: cache size too large");
+               return (EINVAL);
+       }
+#endif
 
-       fd = -1;
-       rp = NULL;
+       /* Intialize the return information in the REGINFO structure. */
+loop:  infop->addr = NULL;
+       infop->fd = -1;
+       infop->segid = INVALID_SEGID;
+       if (infop->name != NULL) {
+               FREES(infop->name);
+               infop->name = NULL;
+       }
+       F_CLR(infop, REGION_CANGROW | REGION_CREATED);
 
+#ifndef HAVE_SPINLOCKS
        /*
-        * Get the filename -- note, if it's a temporary file, it will
-        * be created by the underlying temporary file creation code,
-        * so we have to check the file descriptor to be sure it's an
-        * error.
+        * XXX
+        * Lacking spinlocks, we must have a file descriptor for fcntl(2)
+        * locking, which implies using mmap(2) to map in a regular file.
+        * (Theoretically, we could probably get a file descriptor to lock
+        * other types of shared regions, but I don't see any reason to
+        * bother.)
         */
-       if ((ret = __db_appname(dbenv, appname, path, file, &fd, &name)) != 0)
-               return (ret);
+       malloc_possible = 0;
+#endif
 
+#ifdef __hppa
        /*
-        * Now open the file. We need to make sure that multiple processes
-        * that attempt to create the region at the same time are properly
-        * ordered, so we open it DB_EXCL and DB_CREATE so two simultaneous
-        * attempts to create the region will return failure in one of the
-        * attempts.
+        * XXX
+        * HP-UX won't permit mutexes to live in anything but shared memory.
+        * Instantiate a shared region file on that architecture, regardless.
         */
-       oflags |= DB_CREATE | DB_EXCL;
-       if (fd == -1 &&
-           (ret = __db_open(name, oflags, oflags, mode, &fd)) != 0) {
-               if (ret != EEXIST)
-                       __db_err(dbenv,
-                           "region create: %s: %s", name, strerror(ret));
-               goto err;
+       malloc_possible = 0;
+#endif
+       /*
+        * If a region is truly private, malloc the memory.  That's faster
+        * than either anonymous memory or a shared file.
+        */
+       if (malloc_possible && F_ISSET(infop, REGION_PRIVATE)) {
+               if ((infop->addr = __db_malloc(infop->size)) == NULL)
+                       return (ENOMEM);
+
+               /*
+                * It's sometimes significantly faster to page-fault in all
+                * of the region's pages before we run the application, as
+                * we can see fairly nasty side-effects when we page-fault
+                * while holding various locks, i.e., the lock takes a long
+                * time, and other threads convoy behind the lock holder.
+                */
+               if (DB_GLOBAL(db_region_init))
+                       for (p = infop->addr;
+                           p < (u_int8_t *)infop->addr + infop->size;
+                           p += DB_VMPAGESIZE)
+                               p[0] = '\0';
+
+               F_SET(infop, REGION_CREATED | REGION_MALLOC);
+               goto region_init;
        }
-       *fdp = fd;
 
-       /* Grow the region to the correct size. */
-       if ((ret = __db_rgrow(dbenv, fd, size)) != 0)
-               goto err;
+       /*
+        * Get the name of the region (creating the file if a temporary file
+        * is being used).  The dbenv contains the current DB environment,
+        * including naming information.  The path argument may be a file or
+        * a directory.  If path is a directory, it must exist and file is the
+        * file name to be created inside the directory.  If path is a file,
+        * then file must be NULL.
+        */
+       if ((ret = __db_appname(infop->dbenv, infop->appname, infop->path,
+           infop->file, infop->dbflags, &infop->fd, &infop->name)) != 0)
+               return (ret);
+       if (infop->fd != -1)
+               F_SET(infop, REGION_CREATED);
 
-       /* Map the region in. */
-       if ((ret = __db_rmap(dbenv, fd, size, &rp)) != 0)
-               goto err;
+       /*
+        * Try to create the file, if we have authority.  We have to make sure
+        * that multiple threads/processes attempting to simultaneously create
+        * the region are properly ordered, so we open it using DB_CREATE and
+        * DB_EXCL, so two attempts to create the region will return failure in
+        * one.
+        */
+       if (infop->fd == -1 && infop->dbflags & DB_CREATE) {
+               flags = infop->dbflags;
+               LF_SET(DB_EXCL);
+               if ((ret = __db_open(infop->name,
+                   flags, flags, infop->mode, &infop->fd)) == 0)
+                       F_SET(infop, REGION_CREATED);
+               else
+                       if (ret != EEXIST)
+                               goto errmsg;
+       }
 
-       /* Initialize the region. */
-       if ((ret = __db_rinit(dbenv, rp, fd, size, 1)) != 0)
-               goto err;
+       /* If we couldn't create the file, try and open it. */
+       if (infop->fd == -1) {
+               flags = infop->dbflags;
+               LF_CLR(DB_CREATE | DB_EXCL);
+               if ((ret = __db_open(infop->name,
+                   flags, flags, infop->mode, &infop->fd)) != 0)
+                       goto errmsg;
+       }
 
-       if (name != NULL)
-               FREES(name);
+       /*
+        * There are three cases we support:
+        *    1. Named anonymous memory (shmget(2)).
+        *    2. Unnamed anonymous memory (mmap(2): MAP_ANON/MAP_ANONYMOUS).
+        *    3. Memory backed by a regular file (mmap(2)).
+        *
+        * We instantiate a backing file in all cases, which contains at least
+        * the RLAYOUT structure, and in case #4, contains the actual region.
+        * This is necessary for a couple of reasons:
+        *
+        * First, the mpool region uses temporary files to name regions, and
+        * since you may have multiple regions in the same directory, we need
+        * a filesystem name to ensure that they don't collide.
+        *
+        * Second, applications are allowed to forcibly remove regions, even
+        * if they don't know anything about them other than the name.  If a
+        * region is backed by anonymous memory, there has to be some way for
+        * the application to find out that information, and, in some cases,
+        * determine ID information for the anonymous memory.
+        */
+       if (F_ISSET(infop, REGION_CREATED)) {
+               /*
+                * If we're using anonymous memory to back this region, set
+                * the flag.
+                */
+               if (DB_GLOBAL(db_region_anon))
+                       F_SET(infop, REGION_ANONYMOUS);
 
-       *(void **)retp = rp;
-       return (0);
+               /*
+                * If we're using a regular file to back a region we created,
+                * grow it to the specified size.
+                */
+               if (!DB_GLOBAL(db_region_anon) &&
+                   (ret = __db_growregion(infop, infop->size)) != 0)
+                       goto err;
+       } else {
+               /*
+                * If we're joining a region, figure out what it looks like.
+                *
+                * XXX
+                * We have to figure out if the file is a regular file backing
+                * a region that we want to map into our address space, or a
+                * file with the information we need to find a shared anonymous
+                * region that we want to map into our address space.
+                *
+                * All this noise is because some systems don't have a coherent
+                * VM and buffer cache, and worse, if you mix operations on the
+                * VM and buffer cache, half the time you hang the system.
+                *
+                * There are two possibilities.  If the file is the size of an
+                * RLAYOUT structure, then we know that the real region is in
+                * shared memory, because otherwise it would be bigger.  (As
+                * the RLAYOUT structure size is smaller than a disk sector,
+                * the only way it can be this size is if deliberately written
+                * that way.)  In which case, retrieve the information we need
+                * from the RLAYOUT structure and use it to acquire the shared
+                * memory.
+                *
+                * If the structure is larger than an RLAYOUT structure, then
+                * the file is backing the shared memory region, and we use
+                * the current size of the file without reading any information
+                * from the file itself so that we don't confuse the VM.
+                *
+                * And yes, this makes me want to take somebody and kill them,
+                * but I can't think of any other solution.
+                */
+               if ((ret = __db_ioinfo(infop->name,
+                   infop->fd, &mbytes, &bytes, NULL)) != 0)
+                       goto errmsg;
+               size = mbytes * MEGABYTE + bytes;
+
+               if (size <= sizeof(RLAYOUT)) {
+                       /*
+                        * If the size is too small, the read fails or the
+                        * valid flag is incorrect, assume it's because the
+                        * RLAYOUT information hasn't been written out yet,
+                        * and retry.
+                        */
+                       if (size < sizeof(RLAYOUT))
+                               goto retry;
+                       if ((ret =
+                           __db_read(infop->fd, &rl, sizeof(rl), &nr)) != 0)
+                               goto retry;
+                       if (rl.valid != DB_REGIONMAGIC)
+                               goto retry;
+
+                       /* Copy the size, memory id and characteristics. */
+                       size = rl.size;
+                       infop->segid = rl.segid;
+                       if (F_ISSET(&rl, REGION_ANONYMOUS))
+                               F_SET(infop, REGION_ANONYMOUS);
+               }
 
-err:   if (fd != -1) {
-               if (rp != NULL)
-                       (void)__db_unmap(rp, rp->size);
-               (void)__db_unlink(name);
-               (void)__db_close(fd);
+               /*
+                * If the region is larger than we think, that's okay, use the
+                * current size.  If it's smaller than we think, and we were
+                * just using the default size, that's okay, use the current
+                * size.  If it's smaller than we think and we really care,
+                * save the size and we'll catch that further down -- we can't
+                * correct it here because we have to have a lock to grow the
+                * region.
+                */
+               if (infop->size > size && !F_ISSET(infop, REGION_SIZEDEF))
+                       grow_region = infop->size;
+               infop->size = size;
        }
-       if (name != NULL)
-               FREES(name);
-       return (ret);
-}
-
-/*
- * __db_rinit --
- *     Initialize the region.
- *
- * PUBLIC: int __db_rinit __P((DB_ENV *, RLAYOUT *, int, size_t, int));
- */
-int
-__db_rinit(dbenv, rp, fd, size, lock_region)
-       DB_ENV *dbenv;
-       RLAYOUT *rp;
-       size_t size;
-       int fd, lock_region;
-{
-       int ret;
 
-       COMPQUIET(dbenv, NULL);
+       /*
+        * Map the region into our address space.  If we're creating it, the
+        * underlying routines will make it the right size.
+        *
+        * There are at least two cases where we can "reasonably" fail when
+        * we attempt to map in the region.  On Windows/95, closing the last
+        * reference to a region causes it to be zeroed out.  On UNIX, when
+        * using the shmget(2) interfaces, the region will no longer exist
+        * if the system was rebooted.  In these cases, the underlying map call
+        * returns EAGAIN, and we *remove* our file and try again.  There are
+        * obvious races in doing this, but it should eventually settle down
+        * to a winner and then things should proceed normally.
+        */
+       if ((ret = __db_mapregion(infop->name, infop)) != 0)
+               if (ret == EAGAIN) {
+                       /*
+                        * Pretend we created the region even if we didn't so
+                        * that our error processing unlinks it.
+                        */
+                       F_SET(infop, REGION_CREATED);
+                       ret = 0;
+                       goto retry;
+               } else
+                       goto err;
 
+region_init:
        /*
-        * Initialize the common information.
+        * Initialize the common region information.
         *
         * !!!
         * We have to order the region creates so that two processes don't try
-        * to simultaneously create the region and so that processes that are
-        * joining the region never see inconsistent data.  We'd like to play
-        * file permissions games, but we can't because WNT filesystems won't
-        * open a file mode 0.
-        *
-        * If the lock_region flag is set, the process creating the region
-        * acquires the lock before the setting the version number.  Any
-        * process joining the region checks the version number before
-        * attempting to acquire the lock.  (The lock_region flag may not be
-        * set -- the mpool code sometimes malloc's private regions but still
-        * needs to initialize them, specifically, the mutex for threads.)
+        * to simultaneously create the region.  This is handled by using the
+        * DB_CREATE and DB_EXCL flags when we create the "backing" region file.
         *
-        * We have to check the version number first, because if the version
-        * number has not been written, it's possible that the mutex has not
-        * been initialized in which case an attempt to get it could lead to
-        * random behavior.  If the version number isn't there (the file size
-        * is too small) or it's 0, we know that the region is being created.
-        *
-        * We also make sure to check the return of __db_mutex_lock() here,
-        * even though we don't usually check elsewhere.  This is the first
-        * lock we attempt to acquire, and if it fails we have to know.  (It
-        * can fail -- SunOS, using fcntl(2) for locking, with an in-memory
-        * filesystem specified as the database home.)
+        * We also have to order region joins so that processes joining regions
+        * never see inconsistent data.  We'd like to play permissions games
+        * with the backing file, but we can't because WNT filesystems won't
+        * open a file mode 0.
         */
-       __db_mutex_init(&rp->lock, MUTEX_LOCK_OFFSET(rp, &rp->lock));
-       if (lock_region && (ret = __db_mutex_lock(&rp->lock, fd)) != 0)
-               return (ret);
-
-       rp->refcnt = 1;
-       rp->size = size;
-       rp->flags = 0;
-       db_version(&rp->majver, &rp->minver, &rp->patch);
+       rlp = (RLAYOUT *)infop->addr;
+       if (F_ISSET(infop, REGION_CREATED)) {
+               /*
+                * The process creating the region acquires a lock before it
+                * sets the valid flag.  Any processes joining the region will
+                * check the valid flag before acquiring the lock.
+                *
+                * Check the return of __db_mutex_init() and __db_mutex_lock(),
+                * even though we don't usually check elsewhere.  This is the
+                * first lock we initialize and acquire, and we have to know if
+                * it fails.  (It CAN fail, e.g., SunOS, when using fcntl(2)
+                * for locking, with an in-memory filesystem specified as the
+                * database home.)
+                */
+               if ((ret = __db_mutex_init(&rlp->lock,
+                   MUTEX_LOCK_OFFSET(rlp, &rlp->lock))) != 0 ||
+                   (ret = __db_mutex_lock(&rlp->lock, infop->fd)) != 0)
+                       goto err;
 
-       return (0);
-}
+               /* Initialize the remaining region information. */
+               rlp->refcnt = 1;
+               rlp->size = infop->size;
+               db_version(&rlp->majver, &rlp->minver, &rlp->patch);
+               rlp->segid = infop->segid;
+               rlp->flags = 0;
+               if (F_ISSET(infop, REGION_ANONYMOUS))
+                       F_SET(rlp, REGION_ANONYMOUS);
 
-/*
- * __db_ropen --
- *     Construct the name of a file, open it and map it in.
- *
- * PUBLIC: int __db_ropen __P((DB_ENV *,
- * PUBLIC:    APPNAME, const char *, const char *, int, int *, void *));
- */
-int
-__db_ropen(dbenv, appname, path, file, flags, fdp, retp)
-       DB_ENV *dbenv;
-       APPNAME appname;
-       const char *path, *file;
-       int flags, *fdp;
-       void *retp;
-{
-       RLAYOUT *rp;
-       size_t size;
-       u_int32_t mbytes, bytes;
-       int fd, ret;
-       char *name;
+               /*
+                * Fill in the valid field last -- use a magic number, memory
+                * may not be zero-filled, and we want to minimize the chance
+                * for collision.
+                */
+               rlp->valid = DB_REGIONMAGIC;
 
-       fd = -1;
-       rp = NULL;
+               /*
+                * If the region is anonymous, write the RLAYOUT information
+                * into the backing file so that future region join and unlink
+                * calls can find it.
+                *
+                * XXX
+                * We MUST do the seek before we do the write.  On Win95, while
+                * closing the last reference to an anonymous shared region
+                * doesn't discard the region, it does zero it out.  So, the
+                * REGION_CREATED may be set, but the file may have already
+                * been written and the file descriptor may be at the end of
+                * the file.
+                */
+               if (F_ISSET(infop, REGION_ANONYMOUS)) {
+                       if ((ret = __db_seek(infop->fd, 0, 0, 0, 0, 0)) != 0)
+                               goto err;
+                       if ((ret =
+                           __db_write(infop->fd, rlp, sizeof(*rlp), &nw)) != 0)
+                               goto err;
+               }
+       } else {
+               /*
+                * Check the valid flag to ensure the region is initialized.
+                * If the valid flag has not been set, the mutex may not have
+                * been initialized, and an attempt to get it could lead to
+                * random behavior.
+                */
+               if (rlp->valid != DB_REGIONMAGIC)
+                       goto retry;
 
-       /* Get the filename. */
-       if ((ret = __db_appname(dbenv, appname, path, file, NULL, &name)) != 0)
-               return (ret);
+               /* Get the region lock. */
+               (void)__db_mutex_lock(&rlp->lock, infop->fd);
 
-       /* Open the file. */
-       if ((ret = __db_open(name, flags, DB_MUTEXDEBUG, 0, &fd)) != 0) {
-               __db_err(dbenv, "region open: %s: %s", name, strerror(ret));
-               goto err2;
-       }
+               /*
+                * We now own the region.  There are a couple of things that
+                * may have gone wrong, however.
+                *
+                * Problem #1: while we were waiting for the lock, the region
+                * was deleted.  Detected by re-checking the valid flag, since
+                * it's cleared by the delete region routines.
+                */
+               if (rlp->valid != DB_REGIONMAGIC) {
+                       (void)__db_mutex_unlock(&rlp->lock, infop->fd);
+                       goto retry;
+               }
 
-       *fdp = fd;
+               /*
+                * Problem #2: We want a bigger region than has previously been
+                * created.  Detected by checking if the region is smaller than
+                * our caller requested.  If it is, we grow the region, (which
+                * does the detach and re-attach for us).
+                */
+               if (grow_region != 0 &&
+                   (ret = __db_rgrow(infop, grow_region)) != 0) {
+                       (void)__db_mutex_unlock(&rlp->lock, infop->fd);
+                       goto err;
+               }
 
-       /*
-        * Map the file in.  We have to do things in a strange order so that
-        * we don't get into a situation where the file was just created and
-        * isn't yet initialized.  See the comment in __db_rcreate() above.
-        *
-        * XXX
-        * We'd like to test to see if the file is too big to mmap.  Since we
-        * don't know what size or type off_t's or size_t's are, or the largest
-        * unsigned integral type is, or what random insanity the local C
-        * compiler will perpetrate, doing the comparison in a portable way is
-        * flatly impossible.  Hope that mmap fails if the file is too large.
-        *
-        */
-       if ((ret = __db_ioinfo(name, fd, &mbytes, &bytes, NULL)) != 0) {
-               __db_err(dbenv, "%s: %s", name, strerror(ret));
-               goto err2;
-       }
-       size = mbytes * MEGABYTE + bytes;
+               /*
+                * Problem #3: when we checked the size of the file, it was
+                * still growing as part of creation.  Detected by the fact
+                * that infop->size isn't the same size as the region.
+                */
+               if (infop->size != rlp->size) {
+                       (void)__db_mutex_unlock(&rlp->lock, infop->fd);
+                       goto retry;
+               }
 
-       /* Check to make sure the first block has been written. */
-       if (size < sizeof(RLAYOUT)) {
-               ret = EAGAIN;
-               goto err2;
+               /* Increment the reference count. */
+               ++rlp->refcnt;
        }
 
-       /* Map in whatever is there. */
-       if ((ret = __db_rmap(dbenv, fd, size, &rp)) != 0)
-               goto err2;
+       /* Return the region in a locked condition. */
 
-       /*
-        * Check to make sure the region has been initialized.  We can't just
-        * grab the lock because the lock may not have been initialized yet.
-        */
-       if (rp->majver == 0) {
-               ret = EAGAIN;
-               goto err2;
-       }
-
-       /* Get the region lock. */
-       if (!LF_ISSET(DB_MUTEXDEBUG))
-               (void)__db_mutex_lock(&rp->lock, fd);
+       if (0) {
+errmsg:                __db_err(infop->dbenv, "%s: %s", infop->name, strerror(ret));
 
-       /*
-        * The file may have been half-written if we were descheduled between
-        * getting the size of the file and checking the major version.  Check
-        * to make sure we got the entire file.
-        */
-       if ((ret = __db_ioinfo(name, fd, &mbytes, &bytes, NULL)) != 0) {
-               __db_err(dbenv, "%s: %s", name, strerror(ret));
-               goto err1;
-       }
-       if (size != mbytes * MEGABYTE + bytes) {
-               ret = EAGAIN;
-               goto err1;
-       }
+err:
+retry:         /* Discard the region. */
+               if (infop->addr != NULL) {
+                       (void)__db_unmapregion(infop);
+                       infop->addr = NULL;
+               }
 
-       /* The file may have just been deleted. */
-       if (F_ISSET(rp, DB_R_DELETED)) {
-               ret = EAGAIN;
-               goto err1;
-       }
+               /* Discard the backing file. */
+               if (infop->fd != -1) {
+                       (void)__db_close(infop->fd);
+                       infop->fd = -1;
 
-       /* Increment the reference count. */
-       ++rp->refcnt;
+                       if (F_ISSET(infop, REGION_CREATED))
+                               (void)__db_unlink(infop->name);
+               }
 
-       /* Release the lock. */
-       if (!LF_ISSET(DB_MUTEXDEBUG))
-               (void)__db_mutex_unlock(&rp->lock, fd);
+               /* Discard the name. */
+               if (infop->name != NULL) {
+                       FREES(infop->name);
+                       infop->name = NULL;
+               }
 
-       FREES(name);
+               /*
+                * If we had a temporary error, wait a few seconds and
+                * try again.
+                */
+               if (ret == 0) {
+                       if (++retry_cnt <= 3) {
+                               __db_sleep(retry_cnt * 2, 0);
+                               goto loop;
+                       }
+                       ret = EAGAIN;
+               }
+       }
 
-       *(void **)retp = rp;
-       return (0);
+       /*
+        * XXX
+        * HP-UX won't permit mutexes to live in anything but shared memory.
+        * Instantiate a shared region file on that architecture, regardless.
+        *
+        * XXX
+        * There's a problem in cleaning this up on application exit, or on
+        * application failure.  If an application opens a database without
+        * an environment, we create a temporary backing mpool region for it.
+        * That region is marked REGION_PRIVATE, but as HP-UX won't permit
+        * mutexes to live in anything but shared memory, we instantiate a
+        * real file plus a memory region of some form.  If the application
+        * crashes, the necessary information to delete the backing file and
+        * any system region (e.g., the shmget(2) segment ID) is no longer
+        * available.  We can't completely fix the problem, but we try.
+        *
+        * The underlying UNIX __db_mapregion() code preferentially uses the
+        * mmap(2) interface with the MAP_ANON/MAP_ANONYMOUS flags for regions
+        * that are marked REGION_PRIVATE.  This means that we normally aren't
+        * holding any system resources when we get here, in which case we can
+        * delete the backing file.  This results in a short race, from the
+        * __db_open() call above to here.
+        *
+        * If, for some reason, we are holding system resources when we get
+        * here, we don't have any choice -- we can't delete the backing file
+        * because we may need it to detach from the resources.  Set the
+        * REGION_LASTDETACH flag, so that we do all necessary cleanup when
+        * the application closes the region.
+        */
+       if (F_ISSET(infop, REGION_PRIVATE) && !F_ISSET(infop, REGION_MALLOC))
+               if (F_ISSET(infop, REGION_HOLDINGSYS))
+                       F_SET(infop, REGION_LASTDETACH);
+               else {
+                       F_SET(infop, REGION_REMOVED);
+                       F_CLR(infop, REGION_CANGROW);
+
+                       (void)__db_close(infop->fd);
+                       (void)__db_unlink(infop->name);
+               }
 
-err1:  if (!LF_ISSET(DB_MUTEXDEBUG))
-               (void)__db_mutex_unlock(&rp->lock, fd);
-err2:  if (rp != NULL)
-               (void)__db_unmap(rp, rp->size);
-       if (fd != -1)
-               (void)__db_close(fd);
-       FREES(name);
        return (ret);
 }
 
 /*
- * __db_rclose --
- *     Close a shared memory region.
+ * __db_rdetach --
+ *     De-attach from a shared memory region.
  *
- * PUBLIC: int __db_rclose __P((DB_ENV *, int, void *));
+ * PUBLIC: int __db_rdetach __P((REGINFO *));
  */
 int
-__db_rclose(dbenv, fd, ptr)
-       DB_ENV *dbenv;
-       int fd;
-       void *ptr;
+__db_rdetach(infop)
+       REGINFO *infop;
 {
-       RLAYOUT *rp;
-       int ret, t_ret;
-       const char *fail;
+       RLAYOUT *rlp;
+       int detach, ret, t_ret;
 
-       rp = ptr;
-       fail = NULL;
+       ret = 0;
 
-       /* Get the lock. */
-       if ((ret = __db_mutex_lock(&rp->lock, fd)) != 0) {
-               fail = "lock get";
-               goto err;
+       /*
+        * If the region was removed when it was created, no further action
+        * is required.
+        */
+       if (F_ISSET(infop, REGION_REMOVED))
+               goto done;
+       /*
+        * If the region was created in memory returned by malloc, the only
+        * action required is freeing the memory.
+        */
+       if (F_ISSET(infop, REGION_MALLOC)) {
+               __db_free(infop->addr);
+               goto done;
        }
 
+       /* Otherwise, attach to the region and optionally delete it. */
+       rlp = infop->addr;
+
+       /* Get the lock. */
+       (void)__db_mutex_lock(&rlp->lock, infop->fd);
+
        /* Decrement the reference count. */
-       --rp->refcnt;
+       if (rlp->refcnt == 0)
+               __db_err(infop->dbenv,
+                   "region rdetach: reference count went to zero!");
+       else
+               --rlp->refcnt;
+
+       /*
+        * If we're going to remove the region, clear the valid flag so
+        * that any region join that's blocked waiting for us will know
+        * what happened.
+        */
+       detach = 0;
+       if (F_ISSET(infop, REGION_LASTDETACH))
+               if (rlp->refcnt == 0) {
+                       detach = 1;
+                       rlp->valid = 0;
+               } else
+                       ret = EBUSY;
 
        /* Release the lock. */
-       if ((t_ret = __db_mutex_unlock(&rp->lock, fd)) != 0 && fail == NULL) {
-               ret = t_ret;
-               fail = "lock release";
-       }
+       (void)__db_mutex_unlock(&rlp->lock, infop->fd);
 
-       /* Discard the region. */
-       if ((t_ret = __db_unmap(ptr, rp->size)) != 0 && fail == NULL) {
-               ret = t_ret;
-               fail = "munmap";
-       }
+       /* Close the backing file descriptor. */
+       (void)__db_close(infop->fd);
+       infop->fd = -1;
 
-       if ((t_ret = __db_close(fd)) != 0 && fail == NULL) {
+       /* Discard our mapping of the region. */
+       if ((t_ret = __db_unmapregion(infop)) != 0 && ret == 0)
                ret = t_ret;
-               fail = "close";
+
+       /* Discard the region itself. */
+       if (detach) {
+               if ((t_ret =
+                   __db_unlinkregion(infop->name, infop) != 0) && ret == 0)
+                       ret = t_ret;
+               if ((t_ret = __db_unlink(infop->name) != 0) && ret == 0)
+                       ret = t_ret;
        }
 
-       if (fail == NULL)
-               return (0);
+done:  /* Discard the name. */
+       if (infop->name != NULL) {
+               FREES(infop->name);
+               infop->name = NULL;
+       }
 
-err:   __db_err(dbenv, "region detach: %s: %s", fail, strerror(ret));
        return (ret);
 }
 
 /*
  * __db_runlink --
- *     Remove a shared memory region.
+ *     Remove a region.
  *
- * PUBLIC: int __db_runlink __P((DB_ENV *,
- * PUBLIC:    APPNAME, const char *, const char *, int));
+ * PUBLIC: int __db_runlink __P((REGINFO *, int));
  */
 int
-__db_runlink(dbenv, appname, path, file, force)
-       DB_ENV *dbenv;
-       APPNAME appname;
-       const char *path, *file;
+__db_runlink(infop, force)
+       REGINFO *infop;
        int force;
 {
-       RLAYOUT *rp;
-       int cnt, fd, ret, t_ret;
+       RLAYOUT rl, *rlp;
+       size_t size;
+       ssize_t nr;
+       u_int32_t mbytes, bytes;
+       int fd, ret, t_ret;
        char *name;
 
-       rp = NULL;
+       /*
+        * XXX
+        * We assume that we've created a new REGINFO structure for this
+        * call, not used one that was already initialized.  Regardless,
+        * if anyone is planning to use it after we're done, they're going
+        * to be sorely disappointed.
+        *
+        * If force isn't set, we attach to the region, set a flag to delete
+        * the region on last close, and let the region delete code do the
+        * work.
+        */
+       if (!force) {
+               if ((ret = __db_rattach(infop)) != 0)
+                       return (ret);
 
-       /* Get the filename. */
-       if ((ret = __db_appname(dbenv, appname, path, file, NULL, &name)) != 0)
-               return (ret);
+               rlp = (RLAYOUT *)infop->addr;
+               (void)__db_mutex_unlock(&rlp->lock, infop->fd);
 
-       /* If the file doesn't exist, we're done. */
-       if (__db_exists(name, NULL))
-               goto done;
+               F_SET(infop, REGION_LASTDETACH);
+
+               return (__db_rdetach(infop));
+       }
 
        /*
-        * If we're called with a force flag, try and unlink the file.  This
-        * may not succeed if the file is currently open, but there's nothing
-        * we can do about that.  There is a race condition between the check
-        * for existence above and the actual unlink.  If someone else snuck
-        * in and removed it before we do the remove, then we might get an
-        * ENOENT error.  If we get the ENOENT, we treat it as success, just
-        * as we do above.
+        * Otherwise, we don't want to attach to the region.  We may have been
+        * called to clean up if a process died leaving a region locked and/or
+        * corrupted, which could cause the attach to hang.
         */
-       if (force) {
-               if ((ret = __db_unlink(name)) != 0 && ret != ENOENT)
-                       goto err1;
-               goto done;
+       if ((ret = __db_appname(infop->dbenv, infop->appname,
+           infop->path, infop->file, infop->dbflags, NULL, &name)) != 0)
+               return (ret);
+
+       /*
+        * An underlying file is created for all regions other than private
+        * (REGION_PRIVATE) ones, regardless of whether or not it's used to
+        * back the region.  If that file doesn't exist, we're done.
+        */
+       if (__db_exists(name, NULL) != 0) {
+               FREES(name);
+               return (0);
        }
 
-       /* Open and lock the region. */
-       if ((ret = __db_ropen(dbenv, appname, path, file, 0, &fd, &rp)) != 0)
-               goto err1;
-       (void)__db_mutex_lock(&rp->lock, fd);
+       /*
+        * See the comments in __db_rattach -- figure out if this is a regular
+        * file backing a region or if it's a regular file with information
+        * about a region.
+        */
+       if ((ret = __db_open(name, DB_RDONLY, DB_RDONLY, 0, &fd)) != 0)
+               goto errmsg;
+       if ((ret = __db_ioinfo(name, fd, &mbytes, &bytes, NULL)) != 0)
+               goto errmsg;
+       size = mbytes * MEGABYTE + bytes;
 
-       /* If the region is currently being deleted, fail. */
-       if (F_ISSET(rp, DB_R_DELETED)) {
-               ret = ENOENT;           /* XXX: ENOENT? */
-               goto err2;
-       }
+       if (size <= sizeof(RLAYOUT)) {
+               if ((ret = __db_read(fd, &rl, sizeof(rl), &nr)) != 0)
+                       goto errmsg;
+               if (rl.valid != DB_REGIONMAGIC) {
+                       __db_err(infop->dbenv,
+                           "%s: illegal region magic number", name);
+                       ret = EINVAL;
+                       goto err;
+               }
 
-       /* If the region is currently in use by someone else, fail. */
-       if (rp->refcnt > 1) {
-               ret = EBUSY;
-               goto err2;
+               /* Set the size, memory id and characteristics. */
+               infop->size = rl.size;
+               infop->segid = rl.segid;
+               if (F_ISSET(&rl, REGION_ANONYMOUS))
+                       F_SET(infop, REGION_ANONYMOUS);
+       } else {
+               infop->size = size;
+               infop->segid = INVALID_SEGID;
        }
 
-       /* Set the delete flag. */
-       F_SET(rp, DB_R_DELETED);
-
-       /* Release the lock and close the region. */
-       (void)__db_mutex_unlock(&rp->lock, fd);
-       if ((t_ret = __db_rclose(dbenv, fd, rp)) != 0 && ret == 0)
-               goto err1;
+       /* Remove the underlying region. */
+       ret = __db_unlinkregion(name, infop);
 
        /*
-        * Unlink the region.  There's a race here -- other threads or
-        * processes might be opening the region while we're trying to
-        * remove it.  They'll fail, because we've set the DELETED flag,
-        * but they could still stop us from succeeding in the unlink.
+        * Unlink the backing file.  Close the open file descriptor first,
+        * because some architectures (e.g., Win32) won't unlink a file if
+        * open file descriptors remain.
         */
-       for (cnt = 5; cnt > 0; --cnt) {
-               if ((ret = __db_unlink(name)) == 0)
-                       break;
-               (void)__db_sleep(0, 250000);
-       }
-       if (ret == 0) {
-done:          FREES(name);
-               return (0);
-       }
-
-       /* Not a clue.  Try to clear the DB_R_DELETED flag. */
-       if ((ret = __db_ropen(dbenv, appname, path, file, 0, &fd, &rp)) != 0)
-               goto err1;
-       (void)__db_mutex_lock(&rp->lock, fd);
-       F_CLR(rp, DB_R_DELETED);
-       /* FALLTHROUGH */
+       (void)__db_close(fd);
+       if ((t_ret = __db_unlink(name)) != 0 && ret == 0)
+               ret = t_ret;
 
-err2:  (void)__db_mutex_unlock(&rp->lock, fd);
-       (void)__db_rclose(dbenv, fd, rp);
-err1:  __db_err(dbenv, "region unlink: %s: %s", name, strerror(ret));
+       if (0) {
+errmsg:                __db_err(infop->dbenv, "%s: %s", name, strerror(ret));
+err:           (void)__db_close(fd);
+       }
 
        FREES(name);
        return (ret);
 }
 
 /*
- * DB creates all regions on 4K boundaries so that we don't make the
- * underlying VM unhappy.
- */
-#define        __DB_VMPAGESIZE (4 * 1024)
-
-/*
  * __db_rgrow --
- *     Extend a region by a specified amount.
+ *     Extend a region.
  *
- * PUBLIC: int __db_rgrow __P((DB_ENV *, int, size_t));
+ * PUBLIC: int __db_rgrow __P((REGINFO *, size_t));
  */
 int
-__db_rgrow(dbenv, fd, incr)
-       DB_ENV *dbenv;
-       int fd;
-       size_t incr;
+__db_rgrow(infop, new_size)
+       REGINFO *infop;
+       size_t new_size;
+{
+       RLAYOUT *rlp;
+       size_t increment;
+       int ret;
+
+       /*
+        * !!!
+        * This routine MUST be called with the region already locked.
+        */
+
+       /* The underlying routines have flagged if this region can grow. */
+       if (!F_ISSET(infop, REGION_CANGROW))
+               return (EINVAL);
+
+       /*
+        * Round off the requested size to the next page boundary, and
+        * determine the additional space required.
+        */
+       rlp = (RLAYOUT *)infop->addr;
+       DB_ROUNDOFF(new_size);
+       increment = new_size - rlp->size;
+
+       if ((ret = __db_growregion(infop, increment)) != 0)
+               return (ret);
+
+       /* Update the on-disk region size. */
+       rlp->size = new_size;
+
+       /* Detach from and reattach to the region. */
+       return (__db_rreattach(infop, new_size));
+}
+
+/*
+ * __db_growregion --
+ *     Grow a shared memory region.
+ */
+static int
+__db_growregion(infop, increment)
+       REGINFO *infop;
+       size_t increment;
 {
+       db_pgno_t pages;
        size_t i;
-       ssize_t nw;
-       int mmap_init_needed, ret;
-       char buf[__DB_VMPAGESIZE];
+       ssize_t nr, nw;
+       u_int32_t relative;
+       int ret;
+       char buf[DB_VMPAGESIZE];
 
        /* Seek to the end of the region. */
-       if ((ret = __db_seek(fd, 0, 0, 0, SEEK_END)) != 0)
+       if ((ret = __db_seek(infop->fd, 0, 0, 0, 0, SEEK_END)) != 0)
                goto err;
 
        /* Write nuls to the new bytes. */
        memset(buf, 0, sizeof(buf));
 
        /*
-        * Historically, some systems required that all of the bytes of the
-        * region be written before it could be mmapped and accessed randomly.
-        *
-        * Windows/95 doesn't have that problem, but it leaves file contents
-        * uninitialized.  Win/NT apparently initializes them.
+        * Some systems require that all of the bytes of the region be
+        * written before it can be mapped and accessed randomly, and
+        * other systems don't zero out the pages.
         */
-#ifdef MMAP_INIT_NEEDED
-       mmap_init_needed = 1;
-#else
-       mmap_init_needed = __os_oldwin();
-#endif
-       if (mmap_init_needed)
+       if (__db_mapinit())
                /* Extend the region by writing each new page. */
-               for (i = 0; i < incr; i += __DB_VMPAGESIZE) {
-                       if ((ret = __db_write(fd, buf, sizeof(buf), &nw)) != 0)
+               for (i = 0; i < increment; i += DB_VMPAGESIZE) {
+                       if ((ret =
+                           __db_write(infop->fd, buf, sizeof(buf), &nw)) != 0)
                                goto err;
                        if (nw != sizeof(buf))
                                goto eio;
                }
        else {
                /*
-                * Extend the region by writing the last page.
-                *
-                * Round off the increment to the next page boundary.
+                * Extend the region by writing the last page.  If the region
+                * is >4Gb, increment may be larger than the maximum possible
+                * seek "relative" argument, as it's an unsigned 32-bit value.
+                * Break the offset into pages of 1MB each so that we don't
+                * overflow (2^20 + 2^32 is bigger than any memory I expect
+                * to see for awhile).
                 */
-               incr += __DB_VMPAGESIZE - 1;
-               incr -= incr % __DB_VMPAGESIZE;
-
-               /* Write the last page, not the page after the last. */
-               if ((ret =
-                   __db_seek(fd, 0, 0, incr - __DB_VMPAGESIZE, SEEK_CUR)) != 0)
+               pages = (increment - DB_VMPAGESIZE) / MEGABYTE;
+               relative = (increment - DB_VMPAGESIZE) % MEGABYTE;
+               if ((ret = __db_seek(infop->fd,
+                   MEGABYTE, pages, relative, 0, SEEK_CUR)) != 0)
                        goto err;
-               if ((ret = __db_write(fd, buf, sizeof(buf), &nw)) != 0)
+               if ((ret = __db_write(infop->fd, buf, sizeof(buf), &nw)) != 0)
                        goto err;
                if (nw != sizeof(buf))
                        goto eio;
+
+               /*
+                * It's sometimes significantly faster to page-fault in all
+                * of the region's pages before we run the application, as
+                * we can see fairly nasty side-effects when we page-fault
+                * while holding various locks, i.e., the lock takes a long
+                * time, and other threads convoy behind the lock holder.
+                */
+               if (DB_GLOBAL(db_region_init)) {
+                       pages = increment / MEGABYTE;
+                       relative = increment % MEGABYTE;
+                       if ((ret = __db_seek(infop->fd,
+                           MEGABYTE, pages, relative, 1, SEEK_END)) != 0)
+                               goto err;
+
+                       /* Read a byte from each page. */
+                       for (i = 0; i < increment; i += DB_VMPAGESIZE) {
+                               if ((ret =
+                                   __db_read(infop->fd, buf, 1, &nr)) != 0)
+                                       goto err;
+                               if (nr != 1)
+                                       goto eio;
+                               if ((ret = __db_seek(infop->fd,
+                                   0, 0, DB_VMPAGESIZE - 1, 0, SEEK_CUR)) != 0)
+                                       goto err;
+                       }
+               }
        }
        return (0);
 
 eio:   ret = EIO;
-err:   __db_err(dbenv, "region grow: %s", strerror(ret));
+err:   __db_err(infop->dbenv, "region grow: %s", strerror(ret));
        return (ret);
 }
 
 /*
- * __db_rremap --
- *     Unmap the old region and map in a new region of a new size.  If
- *     either call fails, returns NULL, else returns the address of the
- *     new region.
+ * __db_rreattach --
+ *     Detach from and reattach to a region.
  *
- * PUBLIC: int __db_rremap __P((DB_ENV *, void *, size_t, size_t, int, void *));
+ * PUBLIC: int __db_rreattach __P((REGINFO *, size_t));
  */
 int
-__db_rremap(dbenv, ptr, oldsize, newsize, fd, retp)
-       DB_ENV *dbenv;
-       void *ptr, *retp;
-       size_t oldsize, newsize;
-       int fd;
+__db_rreattach(infop, new_size)
+       REGINFO *infop;
+       size_t new_size;
 {
        int ret;
 
-       if ((ret = __db_unmap(ptr, oldsize)) != 0) {
-               __db_err(dbenv, "region remap: munmap: %s", strerror(ret));
-               return (ret);
+#ifdef DIAGNOSTIC
+       if (infop->name == NULL) {
+               __db_err(infop->dbenv, "__db_rreattach: name was NULL");
+               return (EINVAL);
        }
+#endif
+       /*
+        * If we're growing an already mapped region, we have to unmap it
+        * and get it back.  We have it locked, so nobody else can get in,
+        * which makes it fairly straight-forward to do, as everybody else
+        * is going to block while we do the unmap/remap.  NB: if we fail
+        * to get it back, the pooch is genuinely screwed, because we can
+        * never release the lock we're holding.
+        *
+        * Detach from the region.  We have to do this first so architectures
+        * that don't permit a file to be mapped into different places in the
+        * address space simultaneously, e.g., HP's PaRisc, will work.
+        */
+       if ((ret = __db_unmapregion(infop)) != 0)
+               return (ret);
 
-       return (__db_rmap(dbenv, fd, newsize, retp));
-}
-
-/*
- * __db_rmap --
- *     Attach to a shared memory region.
- */
-static int
-__db_rmap(dbenv, fd, size, retp)
-       DB_ENV *dbenv;
-       int fd;
-       size_t size;
-       void *retp;
-{
-       RLAYOUT *rp;
-       int ret;
+       /* Update the caller's REGINFO size to the new map size. */
+       infop->size = new_size;
 
-       if ((ret = __db_map(fd, size, 0, 0, (void **)&rp)) != 0) {
-               __db_err(dbenv, "region map: mmap %s", strerror(ret));
-               return (ret);
-       }
-       if (rp->size < size)
-               rp->size = size;
+       /* Attach to the region. */
+       ret = __db_mapregion(infop->name, infop);
 
-       *(void **)retp = rp;
-       return (0);
+       return (ret);
 }
index f0202dd..0fa696b 100644 (file)
@@ -1,21 +1,21 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 1996, 1997
+ * Copyright (c) 1996, 1997, 1998
  *     Sleepycat Software.  All rights reserved.
  */
 
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)db_salloc.c  10.6 (Sleepycat) 7/5/97";
+static const char sccsid[] = "@(#)db_salloc.c  10.13 (Sleepycat) 5/10/98";
 #endif /* not lint */
 
 #ifndef NO_SYSTEM_INCLUDES
 #include <sys/types.h>
 
 #include <errno.h>
-#include <stdio.h>
+#include <string.h>
 #endif
 
 #include "db_int.h"
@@ -109,11 +109,13 @@ __db_shalloc(p, len, align, retp)
 
                *(void **)retp = rp;
 
+#define        SHALLOC_FRAGMENT        32
                /*
-                * If there are at least 32 bytes of additional memory, divide
-                * the chunk into two chunks.
+                * If there are at least SHALLOC_FRAGMENT additional bytes of
+                * memory, divide the chunk into two chunks.
                 */
-               if ((u_int8_t *)rp >= (u_int8_t *)&elp->links + 32) {
+               if ((u_int8_t *)rp >=
+                   (u_int8_t *)&elp->links + SHALLOC_FRAGMENT) {
                        sp = rp;
                        *--sp = elp->len -
                            ((u_int8_t *)rp - (u_int8_t *)&elp->links);
@@ -136,7 +138,7 @@ __db_shalloc(p, len, align, retp)
                return (0);
        }
 
-       /* Nothing found large enough; need to figure out how to grow region. */
+       /* Nothing found large enough; need to grow the region. */
        return (ENOMEM);
 }
 
@@ -159,12 +161,18 @@ __db_shalloc_free(regionp, ptr)
         * Step back over flagged length fields to find the beginning of
         * the object and its real size.
         */
-       for (sp = (size_t *)ptr; sp[-1] == ILLEGAL_SIZE; --sp);
+       for (sp = (size_t *)ptr; sp[-1] == ILLEGAL_SIZE; --sp)
+               ;
        ptr = sp;
 
        newp = (struct __data *)((u_int8_t *)ptr - sizeof(size_t));
        free_size = newp->len;
 
+       /* Trash the returned memory. */
+#ifdef DIAGNOSTIC
+       memset(ptr, 0xff, free_size);
+#endif
+
        /*
         * Walk the list, looking for where this entry goes.
         *
@@ -177,7 +185,8 @@ __db_shalloc_free(regionp, ptr)
        hp = (struct __head *)regionp;
        for (elp = SH_LIST_FIRST(hp, __data), lastp = NULL;
            elp != NULL && (void *)elp < (void *)ptr;
-           lastp = elp, elp = SH_LIST_NEXT(elp, links, __data));
+           lastp = elp, elp = SH_LIST_NEXT(elp, links, __data))
+               ;
 
        /*
         * Elp is either NULL (we reached the end of the list), or the slot
@@ -259,32 +268,34 @@ __db_shsizeof(ptr)
         * Step back over flagged length fields to find the beginning of
         * the object and its real size.
         */
-       for (sp = (size_t *)ptr; sp[-1] == ILLEGAL_SIZE; --sp);
+       for (sp = (size_t *)ptr; sp[-1] == ILLEGAL_SIZE; --sp)
+               ;
 
        elp = (struct __data *)((u_int8_t *)sp - sizeof(size_t));
        return (elp->len);
 }
 
-#ifdef DEBUG
 /*
  * __db_shalloc_dump --
  *
- * PUBLIC: void __db_shalloc_dump __P((FILE *, void *));
+ * PUBLIC: void __db_shalloc_dump __P((void *, FILE *));
  */
 void
-__db_shalloc_dump(fp, addr)
-       FILE *fp;
+__db_shalloc_dump(addr, fp)
        void *addr;
+       FILE *fp;
 {
        struct __data *elp;
 
+       /* Make it easy to call from the debugger. */
        if (fp == NULL)
                fp = stderr;
 
+       fprintf(fp, "%s\nMemory free list\n", DB_LINE);
+
        for (elp = SH_LIST_FIRST((struct __head *)addr, __data);
            elp != NULL;
            elp = SH_LIST_NEXT(elp, links, __data))
                fprintf(fp, "%#lx: %lu\t", (u_long)elp, (u_long)elp->len);
        fprintf(fp, "\n");
 }
-#endif
index ab188f5..3f48a55 100644 (file)
@@ -1,14 +1,14 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 1996, 1997
+ * Copyright (c) 1996, 1997, 1998
  *     Sleepycat Software.  All rights reserved.
  */
 
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)db_shash.c   10.4 (Sleepycat) 1/8/98";
+static const char sccsid[] = "@(#)db_shash.c   10.9 (Sleepycat) 4/10/98";
 #endif /* not lint */
 
 #ifndef NO_SYSTEM_INCLUDES
@@ -19,39 +19,75 @@ static const char sccsid[] = "@(#)db_shash.c        10.4 (Sleepycat) 1/8/98";
 #include "shqueue.h"
 #include "common_ext.h"
 
-/* Powers-of-2 and close-by prime number pairs. */
+/*
+ * Table of good hash values.  Up to ~250,000 buckets, we use powers of 2.
+ * After that, we slow the rate of increase by half.  For each choice, we
+ * then use a nearby prime number as the hash value.
+ *
+ * If a terabyte is the maximum cache we'll see, and we assume there are
+ * 10 1K buckets on each hash chain, then 107374182 is the maximum number
+ * of buckets we'll ever need.
+ */
 static const struct {
-       u_int   power;
-       u_int   prime;
+       u_int32_t power;
+       u_int32_t prime;
 } list[] = {
-       {  64,    67},
-       { 128,   131},
-       { 256,   257},
-       { 512,   521},
-       {1024,  1031},
-       {2048,  2053},
-       {4096,  4099},
-       {8192,  8191},
-       {0,        0}
+       {        64,            67},            /* 2^6 */
+       {       128,           131},            /* 2^7 */
+       {       256,           257},            /* 2^8 */
+       {       512,           521},            /* 2^9 */
+       {      1024,          1031},            /* 2^10 */
+       {      2048,          2053},            /* 2^11 */
+       {      4096,          4099},            /* 2^12 */
+       {      8192,          8191},            /* 2^13 */
+       {     16384,         16381},            /* 2^14 */
+       {     32768,         32771},            /* 2^15 */
+       {     65536,         65537},            /* 2^16 */
+       {    131072,        131071},            /* 2^17 */
+       {    262144,        262147},            /* 2^18 */
+       {    393216,        393209},            /* 2^18 + 2^18/2 */
+       {    524288,        524287},            /* 2^19 */
+       {    786432,        786431},            /* 2^19 + 2^19/2 */
+       {   1048576,       1048573},            /* 2^20 */
+       {   1572864,       1572869},            /* 2^20 + 2^20/2 */
+       {   2097152,       2097169},            /* 2^21 */
+       {   3145728,       3145721},            /* 2^21 + 2^21/2 */
+       {   4194304,       4194301},            /* 2^22 */
+       {   6291456,       6291449},            /* 2^22 + 2^22/2 */
+       {   8388608,       8388617},            /* 2^23 */
+       {  12582912,      12582917},            /* 2^23 + 2^23/2 */
+       {  16777216,      16777213},            /* 2^24 */
+       {  25165824,      25165813},            /* 2^24 + 2^24/2 */
+       {  33554432,      33554393},            /* 2^25 */
+       {  50331648,      50331653},            /* 2^25 + 2^25/2 */
+       {  67108864,      67108859},            /* 2^26 */
+       { 100663296,     100663291},            /* 2^26 + 2^26/2 */
+       { 134217728,     134217757},            /* 2^27 */
+       { 201326592,     201326611},            /* 2^27 + 2^27/2 */
+       { 268435456,     268435459},            /* 2^28 */
+       { 402653184,     402653189},            /* 2^28 + 2^28/2 */
+       { 536870912,     536870909},            /* 2^29 */
+       { 805306368,     805306357},            /* 2^29 + 2^29/2 */
+       {1073741824,    1073741827},            /* 2^30 */
+       {0,             0}
 };
 
 /*
  * __db_tablesize --
  *     Choose a size for the hash table.
  *
- * PUBLIC: int __db_tablesize __P((u_int));
+ * PUBLIC: int __db_tablesize __P((u_int32_t));
  */
 int
 __db_tablesize(n_buckets)
-       u_int n_buckets;
+       u_int32_t n_buckets;
 {
        int i;
 
        /*
-        * We try to be clever about how big we make the hash tables.  Pick
-        * a prime number close to the "suggested" number of elements that
-        * will be in the hash table.  We shoot for minimum collisions (i.e.
-        * one element in each bucket).  We use 64 as the minimum table size.
+        * We try to be clever about how big we make the hash tables.  Use a
+        * prime number close to the "suggested" number of elements that will
+        * be in the hash table.  Use 64 as the minimum hash table size.
         *
         * Ref: Sedgewick, Algorithms in C, "Hash Functions"
         */
@@ -73,14 +109,14 @@ __db_tablesize(n_buckets)
  * __db_hashinit --
  *     Initialize a hash table that resides in shared memory.
  *
- * PUBLIC: void __db_hashinit __P((void *, int));
+ * PUBLIC: void __db_hashinit __P((void *, u_int32_t));
  */
 void
 __db_hashinit(begin, nelements)
        void *begin;
-       int nelements;
+       u_int32_t nelements;
 {
-       int i;
+       u_int32_t i;
        SH_TAILQ_HEAD(hash_head) *headp;
 
        headp = (struct hash_head *)begin;
index 7f784a0..e5e1058 100644 (file)
@@ -24,6 +24,9 @@
 /* Define to `unsigned' if <sys/types.h> doesn't define.  */
 /* #undef size_t */
 
+/* Define if the `S_IS*' macros in <sys/stat.h> do not work properly.  */
+/* #undef STAT_MACROS_BROKEN */
+
 /* Define if you have the ANSI C header files.  */
 #define STDC_HEADERS 1
 
 /* Define if you want a debugging version. */
 /* #undef DEBUG */
 
+/* Define if you want a version with run-time diagnostic checking. */
+/* #undef DIAGNOSTIC */
+
 /* Define if you have sigfillset (and sigprocmask). */
 #define HAVE_SIGFILLSET 1
 
-/* Define if seeking to 64-bit file offsets requires the _llseek() call. */
-/* #undef HAVE_LLSEEK */
-
-/* Define if seeking to 64-bit file offsets requires the _lseeki64() call. */
-/* #undef HAVE_LSEEKI */
+/* Define if building on AIX, HP, Solaris to get big-file environment. */
+/* #undef HAVE_FILE_OFFSET_BITS */
+#ifdef HAVE_FILE_OFFSET_BITS
+#define _FILE_OFFSET_BITS 64
+#endif
 
 /* Define if you have spinlocks. */
 /* #undef HAVE_SPINLOCKS */
 /* Define if you want to use mc68020/gcc assembly spinlocks. */
 /* #undef HAVE_ASSEM_MC68020_GCC */
 
+/* Define if you want to use parisc/gcc assembly spinlocks. */
+/* #undef HAVE_ASSEM_PARISC_GCC */
+
+/* Define if you want to use sco/cc assembly spinlocks. */
+/* #undef HAVE_ASSEM_SCO_CC */
+
 /* Define if you want to use sparc/gcc assembly spinlocks. */
 /* #undef HAVE_ASSEM_SPARC_GCC */
 
@@ -69,6 +81,9 @@
 /* Define if you have the SGI abilock_t spinlocks. */
 /* #undef HAVE_FUNC_SGI */
 
+/* Define if you have the ReliantUNIX spinlock_t spinlocks. */
+/* #undef HAVE_FUNC_RELIANT */
+
 /* Define if you have the Solaris mutex_t spinlocks. */
 /* #undef HAVE_FUNC_SOLARIS */
 
 /* Define if you have the select function.  */
 #define HAVE_SELECT 1
 
+/* Define if you have the shmget function.  */
+#define HAVE_SHMGET 1
+
 /* Define if you have the snprintf function.  */
 #define HAVE_SNPRINTF 1
 
-/* Define if you have the strdup function.  */
-#define HAVE_STRDUP 1
-
 /* Define if you have the strerror function.  */
 #define HAVE_STRERROR 1
 
index 6a75bcd..e1f5c72 100644 (file)
--- a/db2/db.h
+++ b/db2/db.h
@@ -1,10 +1,10 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 1996, 1997
+ * Copyright (c) 1996, 1997, 1998
  *     Sleepycat Software.  All rights reserved.
  *
- *     @(#)db.h.src    10.102 (Sleepycat) 1/18/98
+ *     @(#)db.h.src    10.131 (Sleepycat) 6/2/98
  */
 
 #ifndef _DB_H_
@@ -54,8 +54,7 @@
  *
  * !!!
  * We also provide the standard u_int, u_long etc., if they're not provided
- * by the system.  This isn't completely necessary, but the example programs
- * need them.
+ * by the system.
  */
 #ifndef        __BIT_TYPES_DEFINED__
 #define        __BIT_TYPES_DEFINED__
@@ -72,9 +71,9 @@
 
 
 #define        DB_VERSION_MAJOR        2
-#define        DB_VERSION_MINOR        3
-#define        DB_VERSION_PATCH        16
-#define        DB_VERSION_STRING       "Sleepycat Software: DB 2.3.16: (1/19/98)"
+#define        DB_VERSION_MINOR        4
+#define        DB_VERSION_PATCH        14
+#define        DB_VERSION_STRING       "Sleepycat Software: DB 2.4.14: (6/2/98)"
 
 typedef        u_int32_t       db_pgno_t;      /* Page number type. */
 typedef        u_int16_t       db_indx_t;      /* Page offset type. */
@@ -95,6 +94,7 @@ struct __db_bt_stat;  typedef struct __db_bt_stat DB_BTREE_STAT;
 struct __db_dbt;       typedef struct __db_dbt DBT;
 struct __db_env;       typedef struct __db_env DB_ENV;
 struct __db_info;      typedef struct __db_info DB_INFO;
+struct __db_lock_stat; typedef struct __db_lock_stat DB_LOCK_STAT;
 struct __db_lockregion;        typedef struct __db_lockregion DB_LOCKREGION;
 struct __db_lockreq;   typedef struct __db_lockreq DB_LOCKREQ;
 struct __db_locktab;   typedef struct __db_locktab DB_LOCKTAB;
@@ -102,6 +102,7 @@ struct __db_log;    typedef struct __db_log DB_LOG;
 struct __db_log_stat;  typedef struct __db_log_stat DB_LOG_STAT;
 struct __db_lsn;       typedef struct __db_lsn DB_LSN;
 struct __db_mpool;     typedef struct __db_mpool DB_MPOOL;
+struct __db_mpool_finfo;typedef struct __db_mpool_finfo DB_MPOOL_FINFO;
 struct __db_mpool_fstat;typedef struct __db_mpool_fstat DB_MPOOL_FSTAT;
 struct __db_mpool_stat;        typedef struct __db_mpool_stat DB_MPOOL_STAT;
 struct __db_mpoolfile; typedef struct __db_mpoolfile DB_MPOOLFILE;
@@ -134,7 +135,7 @@ struct __db_dbt {
  * There are a set of functions that the application can replace with its
  * own versions, and some other knobs which can be turned at run-time.
  */
-#define        DB_FUNC_CALLOC   1              /* ANSI C calloc. */
+#define        DB_FUNC_CALLOC   1      /* DELETED: ANSI C calloc. */
 #define        DB_FUNC_CLOSE    2              /* POSIX 1003.1 close. */
 #define        DB_FUNC_DIRFREE  3              /* DB: free directory list. */
 #define        DB_FUNC_DIRLIST  4              /* DB: create directory list. */
@@ -149,12 +150,18 @@ struct __db_dbt {
 #define        DB_FUNC_REALLOC 13              /* ANSI C realloc. */
 #define        DB_FUNC_SEEK    14              /* POSIX 1003.1 lseek. */
 #define        DB_FUNC_SLEEP   15              /* DB: sleep secs/usecs. */
-#define        DB_FUNC_STRDUP  16              /* DB: strdup(3). */
+#define        DB_FUNC_STRDUP  16      /* DELETED: DB: strdup(3). */
 #define        DB_FUNC_UNLINK  17              /* POSIX 1003.1 unlink. */
 #define        DB_FUNC_UNMAP   18              /* DB: unmap shared memory file. */
 #define        DB_FUNC_WRITE   19              /* POSIX 1003.1 write. */
 #define        DB_FUNC_YIELD   20              /* DB: yield thread to scheduler. */
 #define        DB_TSL_SPINS    21              /* DB: initialize spin count. */
+#define        DB_FUNC_RUNLINK 22              /* DB: remove a shared region. */
+#define        DB_REGION_ANON  23              /* DB: anonymous, unnamed regions. */
+#define        DB_REGION_INIT  24              /* DB: page-fault regions in create. */
+#define        DB_REGION_NAME  25              /* DB: anonymous, named regions. */
+#define        DB_MUTEXLOCKS   26              /* DB: turn off all mutex locks. */
+#define        DB_PAGEYIELD    27              /* DB: yield the CPU on pool get. */
 
 /*
  * Database configuration and initialization.
@@ -162,52 +169,51 @@ struct __db_dbt {
  /*
   * Flags understood by both db_open(3) and db_appinit(3).
   */
-#define        DB_CREATE               0x00001 /* O_CREAT: create file as necessary. */
-#define        DB_NOMMAP               0x00002 /* Don't mmap underlying file. */
-#define        DB_THREAD               0x00004 /* Free-thread DB package handles. */
+#define        DB_CREATE             0x000001  /* O_CREAT: create file as necessary. */
+#define        DB_NOMMAP             0x000002  /* Don't mmap underlying file. */
+#define        DB_THREAD             0x000004  /* Free-thread DB package handles. */
 
 /*
  * Flags understood by db_appinit(3).
- *
- * DB_MUTEXDEBUG is internal only, and not documented.
  */
-/*                             0x00007    COMMON MASK. */
-#define        DB_INIT_LOCK            0x00008 /* Initialize locking. */
-#define        DB_INIT_LOG             0x00010 /* Initialize logging. */
-#define        DB_INIT_MPOOL           0x00020 /* Initialize mpool. */
-#define        DB_INIT_TXN             0x00040 /* Initialize transactions. */
-#define        DB_MPOOL_PRIVATE        0x00080 /* Mpool: private memory pool. */
-#define        DB_MUTEXDEBUG           0x00100 /* Do not get/set mutexes in regions. */
-#define        DB_RECOVER              0x00200 /* Run normal recovery. */
-#define        DB_RECOVER_FATAL        0x00400 /* Run catastrophic recovery. */
-#define        DB_TXN_NOSYNC           0x00800 /* Do not sync log on commit. */
-#define        DB_USE_ENVIRON          0x01000 /* Use the environment. */
-#define        DB_USE_ENVIRON_ROOT     0x02000 /* Use the environment if root. */
+/*                           0x000007     COMMON MASK. */
+#define        DB_INIT_LOCK          0x000008  /* Initialize locking. */
+#define        DB_INIT_LOG           0x000010  /* Initialize logging. */
+#define        DB_INIT_MPOOL         0x000020  /* Initialize mpool. */
+#define        DB_INIT_TXN           0x000040  /* Initialize transactions. */
+#define        DB_MPOOL_PRIVATE      0x000080  /* Mpool: private memory pool. */
+#define        __UNUSED_100          0x000100
+#define        DB_RECOVER            0x000200  /* Run normal recovery. */
+#define        DB_RECOVER_FATAL      0x000400  /* Run catastrophic recovery. */
+#define        DB_TXN_NOSYNC         0x000800  /* Do not sync log on commit. */
+#define        DB_USE_ENVIRON        0x001000  /* Use the environment. */
+#define        DB_USE_ENVIRON_ROOT   0x002000  /* Use the environment if root. */
 
 /* CURRENTLY UNUSED LOCK FLAGS. */
-#define        DB_TXN_LOCK_2PL         0x00000 /* Two-phase locking. */
-#define        DB_TXN_LOCK_OPTIMISTIC  0x00000 /* Optimistic locking. */
-#define        DB_TXN_LOCK_MASK        0x00000 /* Lock flags mask. */
+#define        DB_TXN_LOCK_2PL       0x000000  /* Two-phase locking. */
+#define        DB_TXN_LOCK_OPTIMIST  0x000000  /* Optimistic locking. */
+#define        DB_TXN_LOCK_MASK      0x000000  /* Lock flags mask. */
 
 /* CURRENTLY UNUSED LOG FLAGS. */
-#define        DB_TXN_LOG_REDO         0x00000 /* Redo-only logging. */
-#define        DB_TXN_LOG_UNDO         0x00000 /* Undo-only logging. */
-#define        DB_TXN_LOG_UNDOREDO     0x00000 /* Undo/redo write-ahead logging. */
-#define        DB_TXN_LOG_MASK         0x00000 /* Log flags mask. */
+#define        DB_TXN_LOG_REDO       0x000000  /* Redo-only logging. */
+#define        DB_TXN_LOG_UNDO       0x000000  /* Undo-only logging. */
+#define        DB_TXN_LOG_UNDOREDO   0x000000  /* Undo/redo write-ahead logging. */
+#define        DB_TXN_LOG_MASK       0x000000  /* Log flags mask. */
 
 /*
  * Flags understood by db_open(3).
  *
- * DB_EXCL and DB_TEMPORARY are internal only, and not documented.
- * DB_SEQUENTIAL is currently internal, but likely to be exported some day.
+ * DB_EXCL and DB_TEMPORARY are internal only, and are not documented.
+ * DB_SEQUENTIAL is currently internal, but may be exported some day.
  */
-/*                             0x00007    COMMON MASK. */
-/*                             0x07fff    ALREADY USED. */
-#define        DB_EXCL                 0x08000 /* O_EXCL: exclusive open. */
-#define        DB_RDONLY               0x10000 /* O_RDONLY: read-only. */
-#define        DB_SEQUENTIAL           0x20000 /* Indicate sequential access. */
-#define        DB_TEMPORARY            0x40000 /* Remove on last close. */
-#define        DB_TRUNCATE             0x80000 /* O_TRUNCATE: replace existing DB. */
+/*                           0x000007     COMMON MASK. */
+/*                           0x003fff     ALREADY USED. */
+#define        __UNUSED_4000         0x004000
+#define        DB_EXCL               0x008000  /* O_EXCL: exclusive open. */
+#define        DB_RDONLY             0x010000  /* O_RDONLY: read-only. */
+#define        DB_SEQUENTIAL         0x020000  /* Indicate sequential access. */
+#define        DB_TEMPORARY          0x040000  /* Remove on last close. */
+#define        DB_TRUNCATE           0x080000  /* O_TRUNCATE: replace existing DB. */
 
 /*
  * Deadlock detector modes; used in the DBENV structure to configure the
@@ -240,9 +246,9 @@ struct __db_env {
        /* Locking. */
        DB_LOCKTAB      *lk_info;       /* Return from lock_open(). */
        u_int8_t        *lk_conflicts;  /* Two dimensional conflict matrix. */
-       int              lk_modes;      /* Number of lock modes in table. */
-       u_int            lk_max;        /* Maximum number of locks. */
-       u_int32_t        lk_detect;     /* Deadlock detect on every conflict. */
+       u_int32_t        lk_modes;      /* Number of lock modes in table. */
+       u_int32_t        lk_max;        /* Maximum number of locks. */
+       u_int32_t        lk_detect;     /* Deadlock detect on all conflicts. */
 
        /* Logging. */
        DB_LOG          *lg_info;       /* Return from log_open(). */
@@ -255,7 +261,7 @@ struct __db_env {
 
        /* Transactions. */
        DB_TXNMGR       *tx_info;       /* Return from txn_open(). */
-       unsigned int     tx_max;        /* Maximum number of transactions. */
+       u_int32_t        tx_max;        /* Maximum number of transactions. */
        int (*tx_recover)               /* Dispatch function for recovery. */
            __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
 
@@ -300,17 +306,17 @@ struct __db_info {
        void *(*db_malloc) __P((size_t));
 
        /* Btree access method. */
-       int              bt_maxkey;     /* Maximum keys per page. */
-       int              bt_minkey;     /* Minimum keys per page. */
+       u_int32_t        bt_maxkey;     /* Maximum keys per page. */
+       u_int32_t        bt_minkey;     /* Minimum keys per page. */
        int (*bt_compare)               /* Comparison function. */
            __P((const DBT *, const DBT *));
        size_t (*bt_prefix)             /* Prefix function. */
            __P((const DBT *, const DBT *));
 
        /* Hash access method. */
-       unsigned int     h_ffactor;     /* Fill factor. */
-       unsigned int     h_nelem;       /* Number of elements. */
-       u_int32_t       (*h_hash)       /* Hash function. */
+       u_int32_t        h_ffactor;     /* Fill factor. */
+       u_int32_t        h_nelem;       /* Number of elements. */
+       u_int32_t      (*h_hash)        /* Hash function. */
            __P((const void *, u_int32_t));
 
        /* Recno access method. */
@@ -353,6 +359,7 @@ struct __db_info {
 #define        DB_SET          0x010000        /* c_get(), log_get() */
 #define        DB_SET_RANGE    0x020000        /* c_get() */
 #define        DB_SET_RECNO    0x040000        /* c_get() */
+#define        DB_CURLSN       0x080000        /* log_put() */
 
 /*
  * DB (user visible) error return codes.
@@ -435,14 +442,14 @@ struct __db {
        void *(*db_malloc) __P((size_t));
 
                                        /* Functions. */
-       int (*close)    __P((DB *, int));
+       int (*close)    __P((DB *, u_int32_t));
        int (*cursor)   __P((DB *, DB_TXN *, DBC **));
-       int (*del)      __P((DB *, DB_TXN *, DBT *, int));
+       int (*del)      __P((DB *, DB_TXN *, DBT *, u_int32_t));
        int (*fd)       __P((DB *, int *));
-       int (*get)      __P((DB *, DB_TXN *, DBT *, DBT *, int));
-       int (*put)      __P((DB *, DB_TXN *, DBT *, DBT *, int));
-       int (*stat)     __P((DB *, void *, void *(*)(size_t), int));
-       int (*sync)     __P((DB *, int));
+       int (*get)      __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t));
+       int (*put)      __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t));
+       int (*stat)     __P((DB *, void *, void *(*)(size_t), u_int32_t));
+       int (*sync)     __P((DB *, u_int32_t));
 
 #define        DB_AM_DUP       0x000001        /* DB_DUP (internal). */
 #define        DB_AM_INMEM     0x000002        /* In-memory; no sync on close. */
@@ -483,9 +490,9 @@ struct __dbc {
        void     *internal;             /* Access method private. */
 
        int (*c_close)  __P((DBC *));
-       int (*c_del)    __P((DBC *, int));
-       int (*c_get)    __P((DBC *, DBT *, DBT *, int));
-       int (*c_put)    __P((DBC *, DBT *, DBT *, int));
+       int (*c_del)    __P((DBC *, u_int32_t));
+       int (*c_get)    __P((DBC *, DBT *, DBT *, u_int32_t));
+       int (*c_put)    __P((DBC *, DBT *, DBT *, u_int32_t));
 };
 
 /* Btree/recno statistics structure. */
@@ -524,10 +531,11 @@ struct __db_bt_stat {
 #if defined(__cplusplus)
 extern "C" {
 #endif
-int   db_appinit __P((const char *, char * const *, DB_ENV *, int));
+int   db_appinit __P((const char *, char * const *, DB_ENV *, u_int32_t));
 int   db_appexit __P((DB_ENV *));
 int   db_jump_set __P((void *, int));
-int   db_open __P((const char *, DBTYPE, int, int, DB_ENV *, DB_INFO *, DB **));
+int   db_open __P((const char *,
+         DBTYPE, u_int32_t, int, DB_ENV *, DB_INFO *, DB **));
 int   db_value_set __P((int, int));
 char *db_version __P((int *, int *, int *));
 #if defined(__cplusplus)
@@ -575,6 +583,21 @@ typedef enum {
        DB_LOCK_IWR                     /* Intent to read and write. */
 } db_lockmode_t;
 
+/*
+ * Status of a lock.
+ */
+typedef enum {
+       DB_LSTAT_ABORTED,               /* Lock belongs to an aborted txn. */
+       DB_LSTAT_ERR,                   /* Lock is bad. */
+       DB_LSTAT_FREE,                  /* Lock is unallocated. */
+       DB_LSTAT_HELD,                  /* Lock is currently held. */
+       DB_LSTAT_NOGRANT,               /* Lock was not granted. */
+       DB_LSTAT_PENDING,               /* Lock was waiting and has been
+                                        * promoted; waiting for the owner
+                                        * to run and upgrade it to held. */
+       DB_LSTAT_WAITING                /* Lock is on the wait queue. */
+} db_status_t;
+
 /* Lock request structure. */
 struct __db_lockreq {
        db_lockop_t      op;            /* Operation. */
@@ -596,19 +619,38 @@ extern const u_int8_t db_rw_conflicts[];
 #define        DB_LOCK_RIW_N   6
 extern const u_int8_t db_riw_conflicts[];
 
+struct __db_lock_stat {
+       u_int32_t st_magic;             /* Lock file magic number. */
+       u_int32_t st_version;           /* Lock file version number. */
+       u_int32_t st_maxlocks;          /* Maximum number of locks in table. */
+       u_int32_t st_nmodes;            /* Number of lock modes. */
+       u_int32_t st_numobjs;           /* Number of objects. */
+       u_int32_t st_nlockers;          /* Number of lockers. */
+       u_int32_t st_nconflicts;        /* Number of lock conflicts. */
+       u_int32_t st_nrequests;         /* Number of lock gets. */
+       u_int32_t st_nreleases;         /* Number of lock puts. */
+       u_int32_t st_ndeadlocks;        /* Number of lock deadlocks. */
+       u_int32_t st_region_wait;       /* Region lock granted after wait. */
+       u_int32_t st_region_nowait;     /* Region lock granted without wait. */
+       u_int32_t st_refcnt;            /* Region reference count. */
+       u_int32_t st_regsize;           /* Region size. */
+};
+
 #if defined(__cplusplus)
 extern "C" {
 #endif
 int      lock_close __P((DB_LOCKTAB *));
-int      lock_detect __P((DB_LOCKTAB *, int, int));
+int      lock_detect __P((DB_LOCKTAB *, u_int32_t, u_int32_t));
 int      lock_get __P((DB_LOCKTAB *,
-           u_int32_t, int, const DBT *, db_lockmode_t, DB_LOCK *));
+           u_int32_t, u_int32_t, const DBT *, db_lockmode_t, DB_LOCK *));
 int      lock_id __P((DB_LOCKTAB *, u_int32_t *));
-int      lock_open __P((const char *, int, int, DB_ENV *, DB_LOCKTAB **));
+int      lock_open __P((const char *,
+           u_int32_t, int, DB_ENV *, DB_LOCKTAB **));
 int      lock_put __P((DB_LOCKTAB *, DB_LOCK));
+int      lock_stat __P((DB_LOCKTAB *, DB_LOCK_STAT **, void *(*)(size_t)));
 int      lock_unlink __P((const char *, int, DB_ENV *));
 int      lock_vec __P((DB_LOCKTAB *,
-           u_int32_t, int, DB_LOCKREQ *, int, DB_LOCKREQ **));
+           u_int32_t, u_int32_t, DB_LOCKREQ *, int, DB_LOCKREQ **));
 #if defined(__cplusplus)
 }
 #endif
@@ -651,19 +693,21 @@ struct __db_log_stat {
        u_int32_t st_region_nowait;     /* Region lock granted without wait. */
        u_int32_t st_cur_file;          /* Current log file number. */
        u_int32_t st_cur_offset;        /* Current log file offset. */
+       u_int32_t st_refcnt;            /* Region reference count. */
+       u_int32_t st_regsize;           /* Region size. */
 };
 
 #if defined(__cplusplus)
 extern "C" {
 #endif
-int     log_archive __P((DB_LOG *, char **[], int, void *(*)(size_t)));
+int     log_archive __P((DB_LOG *, char **[], u_int32_t, void *(*)(size_t)));
 int     log_close __P((DB_LOG *));
 int     log_compare __P((const DB_LSN *, const DB_LSN *));
 int     log_file __P((DB_LOG *, const DB_LSN *, char *, size_t));
 int     log_flush __P((DB_LOG *, const DB_LSN *));
-int     log_get __P((DB_LOG *, DB_LSN *, DBT *, int));
-int     log_open __P((const char *, int, int, DB_ENV *, DB_LOG **));
-int     log_put __P((DB_LOG *, DB_LSN *, const DBT *, int));
+int     log_get __P((DB_LOG *, DB_LSN *, DBT *, u_int32_t));
+int     log_open __P((const char *, u_int32_t, int, DB_ENV *, DB_LOG **));
+int     log_put __P((DB_LOG *, DB_LSN *, const DBT *, u_int32_t));
 int     log_register __P((DB_LOG *, DB *, const char *, DBTYPE, u_int32_t *));
 int     log_stat __P((DB_LOG *, DB_LOG_STAT **, void *(*)(size_t)));
 int     log_unlink __P((const char *, int, DB_ENV *));
@@ -705,6 +749,17 @@ struct __db_mpool_stat {
        u_int32_t st_page_trickle;      /* Pages written by memp_trickle. */
        u_int32_t st_region_wait;       /* Region lock granted after wait. */
        u_int32_t st_region_nowait;     /* Region lock granted without wait. */
+       u_int32_t st_refcnt;            /* Region reference count. */
+       u_int32_t st_regsize;           /* Region size. */
+};
+
+/* Mpool file open information structure. */
+struct __db_mpool_finfo {
+       int        ftype;               /* File type. */
+       DBT       *pgcookie;            /* Byte-string passed to pgin/pgout. */
+       u_int8_t  *fileid;              /* Unique file ID. */
+       int32_t    lsn_offset;          /* LSN offset in page. */
+       u_int32_t  clear_len;           /* Cleared length on created pages. */
 };
 
 /* Mpool file statistics structure. */
@@ -724,13 +779,13 @@ extern "C" {
 #endif
 int    memp_close __P((DB_MPOOL *));
 int    memp_fclose __P((DB_MPOOLFILE *));
-int    memp_fget __P((DB_MPOOLFILE *, db_pgno_t *, int, void *));
+int    memp_fget __P((DB_MPOOLFILE *, db_pgno_t *, u_int32_t, void *));
 int    memp_fopen __P((DB_MPOOL *, const char *,
-           int, int, int, size_t, int, DBT *, u_int8_t *, DB_MPOOLFILE **));
-int    memp_fput __P((DB_MPOOLFILE *, void *, int));
-int    memp_fset __P((DB_MPOOLFILE *, void *, int));
+           u_int32_t, int, size_t, DB_MPOOL_FINFO *, DB_MPOOLFILE **));
+int    memp_fput __P((DB_MPOOLFILE *, void *, u_int32_t));
+int    memp_fset __P((DB_MPOOLFILE *, void *, u_int32_t));
 int    memp_fsync __P((DB_MPOOLFILE *));
-int    memp_open __P((const char *, int, int, DB_ENV *, DB_MPOOL **));
+int    memp_open __P((const char *, u_int32_t, int, DB_ENV *, DB_MPOOL **));
 int    memp_register __P((DB_MPOOL *, int,
            int (*)(db_pgno_t, void *, DBT *),
            int (*)(db_pgno_t, void *, DBT *)));
@@ -765,16 +820,21 @@ struct __db_txn_active {
 };
 
 struct __db_txn_stat {
-       DB_LSN          st_last_ckp;    /* lsn of the last checkpoint */
-       DB_LSN          st_pending_ckp; /* last checkpoint did not finish */
-       time_t          st_time_ckp;    /* time of last checkpoint */
-       u_int32_t       st_last_txnid;  /* last transaction id given out */
-       u_int32_t       st_maxtxns;     /* maximum number of active txns */
-       u_int32_t       st_naborts;     /* number of aborted transactions */
-       u_int32_t       st_nbegins;     /* number of begun transactions */
-       u_int32_t       st_ncommits;    /* number of committed transactions */
-       u_int32_t       st_nactive;     /* number of active transactions */
-       DB_TXN_ACTIVE   *st_txnarray;   /* array of active transactions */
+       DB_LSN    st_last_ckp;          /* lsn of the last checkpoint */
+       DB_LSN    st_pending_ckp;       /* last checkpoint did not finish */
+       time_t    st_time_ckp;          /* time of last checkpoint */
+       u_int32_t st_last_txnid;        /* last transaction id given out */
+       u_int32_t st_maxtxns;   /* maximum number of active txns */
+       u_int32_t st_naborts;   /* number of aborted transactions */
+       u_int32_t st_nbegins;   /* number of begun transactions */
+       u_int32_t st_ncommits;  /* number of committed transactions */
+       u_int32_t st_nactive;   /* number of active transactions */
+       DB_TXN_ACTIVE
+                *st_txnarray;  /* array of active transactions */
+       u_int32_t st_region_wait;       /* Region lock granted after wait. */
+       u_int32_t st_region_nowait;     /* Region lock granted without wait. */
+       u_int32_t st_refcnt;            /* Region reference count. */
+       u_int32_t st_regsize;           /* Region size. */
 };
 
 #if defined(__cplusplus)
@@ -782,11 +842,11 @@ extern "C" {
 #endif
 int      txn_abort __P((DB_TXN *));
 int      txn_begin __P((DB_TXNMGR *, DB_TXN *, DB_TXN **));
-int      txn_checkpoint __P((const DB_TXNMGR *, int, int));
+int      txn_checkpoint __P((const DB_TXNMGR *, u_int32_t, u_int32_t));
 int      txn_commit __P((DB_TXN *));
 int      txn_close __P((DB_TXNMGR *));
 u_int32_t txn_id __P((DB_TXN *));
-int      txn_open __P((const char *, int, int, DB_ENV *, DB_TXNMGR **));
+int      txn_open __P((const char *, u_int32_t, int, DB_ENV *, DB_TXNMGR **));
 int      txn_prepare __P((DB_TXN *));
 int      txn_stat __P((DB_TXNMGR *, DB_TXN_STAT **, void *(*)(size_t)));
 int      txn_unlink __P((const char *, int, DB_ENV *));
@@ -810,10 +870,17 @@ int         txn_unlink __P((const char *, int, DB_ENV *));
  */
 #define        DBM_SUFFIX      ".db"
 
+#if defined(_XPG4_2)
+typedef struct {
+       char *dptr;
+       size_t dsize;
+} datum;
+#else
 typedef struct {
        char *dptr;
        int dsize;
 } datum;
+#endif
 
 /*
  * Translate DBM calls into DB calls so that DB doesn't step on the
@@ -894,7 +961,7 @@ typedef enum {
 
 typedef struct entry {
        char *key;
-       void *data;
+       char *data;
 } ENTRY;
 
 /*
@@ -909,7 +976,7 @@ typedef struct entry {
 #if defined(__cplusplus)
 extern "C" {
 #endif
-int     __db_hcreate __P((unsigned int));
+int     __db_hcreate __P((size_t));
 void    __db_hdestroy __P((void));
 ENTRY  *__db_hsearch __P((ENTRY, ACTION));
 #if defined(__cplusplus)
index 8df7634..9951ebd 100644 (file)
@@ -1,7 +1,7 @@
 /*-
  * See the file LICENSE for redistribution information.
  *
- * Copyright (c) 1996, 1997
+ * Copyright (c) 1996, 1997, 1998
  *     Sleepycat Software.  All rights reserved.
  */
 /*
 #include "config.h"
 
 #ifndef lint
-static const char sccsid[] = "@(#)db.c 10.45 (Sleepycat) 12/4/97";
+static const char sccsid[] = "@(#)db.c 10.57 (Sleepycat) 5/7/98";
 #endif /* not lint */
 
 #ifndef NO_SYSTEM_INCLUDES
 #include <sys/types.h>
-#include <sys/stat.h>
 
 #include <errno.h>
-#include <fcntl.h>
 #include <stddef.h>
-#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <unistd.h>
 #endif
 
 #include "db_int.h"
@@ -71,7 +67,7 @@ static const char sccsid[] = "@(#)db.c        10.45 (Sleepycat) 12/4/97";
 #include "db_am.h"
 #include "common_ext.h"
 
-static int db_close __P((DB *, int));
+static int db_close __P((DB *, u_int32_t));
 static int db_fd __P((DB *, int *));
 
 /*
@@ -99,7 +95,8 @@ int
 db_open(fname, type, flags, mode, dbenv, dbinfo, dbpp)
        const char *fname;
        DBTYPE type;
-       int flags, mode;
+       u_int32_t flags;
+       int mode;
        DB_ENV *dbenv;
        DB_INFO *dbinfo;
        DB **dbpp;
@@ -108,6 +105,7 @@ db_open(fname, type, flags, mode, dbenv, dbinfo, dbpp)
        DB *dbp;
        DBT pgcookie;
        DB_ENV *envp, t_dbenv;
+       DB_MPOOL_FINFO finfo;
        DB_PGINFO pginfo;
        HASHHDR *hashm;
        size_t cachesize;
@@ -125,10 +123,26 @@ db_open(fname, type, flags, mode, dbenv, dbinfo, dbpp)
        if ((ret = __db_fchk(dbenv, "db_open", flags, OKFLAGS)) != 0)
                return (ret);
 
-       if (dbenv != NULL &&
-           LF_ISSET(DB_THREAD) && !F_ISSET(dbenv, DB_ENV_THREAD)) {
-               __db_err(dbenv, "environment not created using DB_THREAD");
-               return (EINVAL);
+       if (dbenv != NULL) {
+               /*
+                * You can't specify threads during the db_open() if the
+                * environment wasn't configured with them.
+                */
+               if (LF_ISSET(DB_THREAD) && !F_ISSET(dbenv, DB_ENV_THREAD)) {
+                       __db_err(dbenv,
+                           "environment not created using DB_THREAD");
+                       return (EINVAL);
+               }
+
+               /*
+                * Specifying a cachesize to db_open(3), after creating an
+                * environment, is a common mistake.
+                */
+               if (dbinfo != NULL && dbinfo->db_cachesize != 0) {
+                       __db_err(dbenv,
+                           "cachesize will be ignored if environment exists");
+                       return (EINVAL);
+               }
        }
 
        /* Initialize for error return. */
@@ -203,7 +217,7 @@ db_open(fname, type, flags, mode, dbenv, dbinfo, dbpp)
 
        /* Fill in the default file mode. */
        if (mode == 0)
-               mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
+               mode = __db_omode("rwrw--");
 
        /* Check if the user wants us to swap byte order. */
        if (dbinfo != NULL)
@@ -230,7 +244,7 @@ db_open(fname, type, flags, mode, dbenv, dbinfo, dbpp)
        if (fname != NULL && fname[0] != '\0') {
                /* Get the real file name. */
                if ((ret = __db_appname(dbenv,
-                    DB_APP_DATA, NULL, fname, NULL, &real_name)) != 0)
+                    DB_APP_DATA, NULL, fname, 0, NULL, &real_name)) != 0)
                        goto err;
 
                /*
@@ -455,22 +469,6 @@ empty:     /*
        }
 
        /*
-        * Set and/or correct the cache size; must be a multiple of the
-        * page size.
-        */
-       if (dbinfo == NULL || dbinfo->db_cachesize == 0)
-               cachesize = dbp->pgsize * DB_MINCACHE;
-       else {
-               cachesize = dbinfo->db_cachesize;
-               if (cachesize & (dbp->pgsize - 1))
-                       cachesize += (~cachesize & (dbp->pgsize - 1)) + 1;
-               if (cachesize < dbp->pgsize * DB_MINCACHE)
-                       cachesize = dbp->pgsize * DB_MINCACHE;
-               if (cachesize < 20 * 1024)
-                       cachesize = 20 * 1024;
-       }
-
-       /*
         * If no mpool supplied by the application, attach to a local,
         * created buffer pool.
         *
@@ -499,10 +497,28 @@ empty:    /*
                        envp = dbenv;
                        restore = 1;
                }
+
+               /*
+                * Set and/or correct the cache size; must be a multiple of</