aboutsummaryrefslogtreecommitdiff
path: root/db2/db
diff options
context:
space:
mode:
Diffstat (limited to 'db2/db')
-rw-r--r--db2/db/db.c818
-rw-r--r--db2/db/db.src154
-rw-r--r--db2/db/db_auto.c1462
-rw-r--r--db2/db/db_conv.c219
-rw-r--r--db2/db/db_dispatch.c270
-rw-r--r--db2/db/db_dup.c680
-rw-r--r--db2/db/db_overflow.c383
-rw-r--r--db2/db/db_pr.c785
-rw-r--r--db2/db/db_rec.c623
-rw-r--r--db2/db/db_ret.c149
-rw-r--r--db2/db/db_thread.c125
11 files changed, 5668 insertions, 0 deletions
diff --git a/db2/db/db.c b/db2/db/db.c
new file mode 100644
index 0000000000..df3a9d2d21
--- /dev/null
+++ b/db2/db/db.c
@@ -0,0 +1,818 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1996, 1997
+ * Sleepycat Software. All rights reserved.
+ */
+/*
+ * Copyright (c) 1990, 1993, 1994, 1995, 1996
+ * Keith Bostic. All rights reserved.
+ */
+/*
+ * Copyright (c) 1990, 1993, 1994, 1995
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#ifndef lint
+static const char sccsid[] = "@(#)db.c 10.37 (Sleepycat) 8/23/97";
+#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"
+#include "shqueue.h"
+#include "db_page.h"
+#include "db_shash.h"
+#include "db_swap.h"
+#include "btree.h"
+#include "hash.h"
+#include "mp.h"
+#include "db_am.h"
+#include "common_ext.h"
+
+static int db_close __P((DB *, int));
+static int db_fd __P((DB *, int *));
+
+/*
+ * If the metadata page has the flag set, set the local flag. If the page
+ * does NOT have the flag set, return EINVAL if the user's dbinfo argument
+ * caused us to already set the local flag.
+ */
+#define DBINFO_FCHK(dbp, fn, meta_flags, m_name, dbp_name) { \
+ if ((meta_flags) & (m_name)) \
+ F_SET(dbp, dbp_name); \
+ else \
+ if (F_ISSET(dbp, dbp_name)) { \
+ __db_err(dbenv, \
+ "%s: %s specified in dbinfo argument but not set in file", \
+ fname, fn); \
+ goto einval; \
+ } \
+}
+
+/*
+ * db_open --
+ * Main library interface to the DB access methods.
+ */
+int
+db_open(fname, type, flags, mode, dbenv, dbinfo, dbpp)
+ const char *fname;
+ DBTYPE type;
+ int flags, mode;
+ DB_ENV *dbenv;
+ DB_INFO *dbinfo;
+ DB **dbpp;
+{
+ BTMETA *btm;
+ DB *dbp;
+ DBT pgcookie;
+ DB_ENV *envp, t_dbenv;
+ DB_PGINFO pginfo;
+ HASHHDR *hashm;
+ off_t io;
+ size_t cachesize;
+ ssize_t nr;
+ int fd, ftype, need_fileid, restore, ret, retry_cnt, swapped;
+ char *real_name, mbuf[512];
+
+ /* Validate arguments. */
+#ifdef HAVE_SPINLOCKS
+#define OKFLAGS (DB_CREATE | DB_NOMMAP | DB_RDONLY | DB_THREAD | DB_TRUNCATE)
+#else
+#define OKFLAGS (DB_CREATE | DB_NOMMAP | DB_RDONLY | DB_TRUNCATE)
+#endif
+ if ((ret = __db_fchk(dbenv, "db_open", flags, OKFLAGS)) != 0)
+ return (ret);
+
+ /* Initialize for error return. */
+ fd = -1;
+ need_fileid = 1;
+ real_name = NULL;
+
+ /* Allocate the DB structure, reference the DB_ENV structure. */
+ if ((dbp = (DB *)calloc(1, sizeof(DB))) == NULL) {
+ __db_err(dbenv, "%s", strerror(ENOMEM));
+ return (ENOMEM);
+ }
+ dbp->dbenv = dbenv;
+
+ /* Convert the dbinfo flags. */
+ if (dbinfo != NULL) {
+ /*
+ * !!!
+ * We can't check for illegal flags until we know what type
+ * of open we're doing.
+ */
+ if (F_ISSET(dbinfo, DB_DELIMITER))
+ F_SET(dbp, DB_RE_DELIMITER);
+ if (F_ISSET(dbinfo, DB_DUP))
+ F_SET(dbp, DB_AM_DUP);
+ if (F_ISSET(dbinfo, DB_FIXEDLEN))
+ F_SET(dbp, DB_RE_FIXEDLEN);
+ if (F_ISSET(dbinfo, DB_PAD))
+ F_SET(dbp, DB_RE_PAD);
+ if (F_ISSET(dbinfo, DB_RECNUM))
+ F_SET(dbp, DB_BT_RECNUM);
+ if (F_ISSET(dbinfo, DB_RENUMBER))
+ F_SET(dbp, DB_RE_RENUMBER);
+ if (F_ISSET(dbinfo, DB_SNAPSHOT))
+ F_SET(dbp, DB_RE_SNAPSHOT);
+ }
+
+ /* Set based on the open(2) flags. */
+ if (LF_ISSET(DB_RDONLY))
+ F_SET(dbp, DB_AM_RDONLY);
+
+ /* Check threading fields. */
+ if (LF_ISSET(DB_THREAD)) {
+ if ((dbp->mutex =
+ (db_mutex_t *)malloc(sizeof(db_mutex_t))) == NULL) {
+ __db_err(dbenv, "%s", strerror(ENOMEM));
+ ret = ENOMEM;
+ goto err;
+ }
+ __db_mutex_init(dbp->mutex, 0);
+
+ F_SET(dbp, DB_AM_THREAD);
+ }
+
+ /*
+ * Always set the master and initialize the queues, so we can
+ * use these fields without checking the thread bit.
+ */
+ dbp->master = dbp;
+ LIST_INIT(&dbp->handleq);
+ LIST_INSERT_HEAD(&dbp->handleq, dbp, links);
+ TAILQ_INIT(&dbp->curs_queue);
+
+ /*
+ * Set based on the dbenv fields, although no logging or transactions
+ * are possible for temporary files.
+ */
+ if (dbp->dbenv != NULL) {
+ if (dbenv->lk_info != NULL)
+ F_SET(dbp, DB_AM_LOCKING);
+ if (fname != NULL && dbenv->lg_info != NULL)
+ F_SET(dbp, DB_AM_LOGGING);
+ }
+
+ /* Set the common fields. */
+ if (dbinfo == NULL) {
+ dbp->pgsize = 0;
+ dbp->db_malloc = NULL;
+ } else {
+ dbp->pgsize = dbinfo->db_pagesize;
+ dbp->db_malloc = dbinfo->db_malloc;
+ }
+
+ /* Fill in the default file mode. */
+ if (mode == 0)
+ mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
+
+ /* Check if the user wants us to swap byte order. */
+ if (dbinfo != NULL)
+ switch (ret = __db_byteorder(dbenv, dbinfo->db_lorder)) {
+ case 0:
+ break;
+ case DB_SWAPBYTES:
+ F_SET(dbp, DB_AM_SWAP);
+ break;
+ default:
+ goto err;
+ }
+
+ /*
+ * If we have a file name, try and read the first page, figure out
+ * what type of file it is, and initialize everything we can based
+ * on that file's meta-data page.
+ *
+ * XXX
+ * We don't actually expect zero-length strings as arguments. We
+ * do the check, permitting them, because scripting languages, e.g.,
+ * the Tcl test suite, doesn't know anything about passing NULL's.
+ */
+ 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)
+ goto err;
+
+ /*
+ * Open the backing file. We need to make sure that multiple
+ * processes attempting to create the file at the same time
+ * are properly ordered so that only one of them creates the
+ * "unique" file id, so we open it O_EXCL and O_CREAT so two
+ * simultaneous attempts to create the region will return
+ * failure in one of the attempts. If we're one of the ones
+ * that fail, we simply retry without the O_CREAT flag, which
+ * will require that the meta-data page exist.
+ */
+#undef OKFLAGS
+#define OKFLAGS \
+ DB_CREATE | DB_NOMMAP | DB_RDONLY | DB_THREAD | DB_TRUNCATE
+ retry_cnt = 0;
+open_retry: if (LF_ISSET(DB_CREATE)) {
+ if ((ret = __db_fdopen(real_name, flags | DB_EXCL,
+ OKFLAGS | DB_EXCL, mode, &fd)) != 0)
+ if (ret == EEXIST) {
+ LF_CLR(DB_CREATE);
+ goto open_retry;
+ } else {
+ __db_err(dbenv,
+ "%s: %s", fname, strerror(ret));
+ goto err;
+ }
+ } else
+ if ((ret = __db_fdopen(real_name,
+ flags, OKFLAGS, mode, &fd)) != 0) {
+ __db_err(dbenv, "%s: %s", fname, strerror(ret));
+ goto err;
+ }
+
+ /*
+ * Use the optimum I/O size as the pagesize if a pagesize not
+ * specified. Some filesystems have 64K as their optimum I/O
+ * size, but as that results in impossibly large default cache
+ * sizes, we limit the default pagesize to 16K.
+ */
+ if (dbp->pgsize == 0) {
+ if ((ret = __db_stat(dbp->dbenv,
+ real_name, fd, NULL, &io)) != 0)
+ goto err;
+ if (io < 512)
+ io = 512;
+ if (io > 16 * 1024)
+ io = 16 * 1024;
+ dbp->pgsize = io;
+ F_SET(dbp, DB_AM_PGDEF);
+ }
+
+ /*
+ * Try and read the first disk sector -- this code assumes
+ * that the meta-data for all access methods fits in 512
+ * bytes, and that no database will be smaller than that.
+ */
+ if ((ret = __db_read(fd, mbuf, sizeof(mbuf), &nr)) != 0)
+ goto err;
+
+ /* The fd is no longer needed. */
+ (void)__db_close(fd);
+ fd = -1;
+
+ if (nr != sizeof(mbuf)) {
+ if (nr != 0) {
+ __db_err(dbenv,
+ "%s: unexpected file format", fname);
+ goto einval;
+ }
+ /*
+ * The only way we can reach here with the DB_CREATE
+ * flag set is if we created the file. If we didn't
+ * create the file, there's a chance that someone else
+ * is busily doing so. Sleep and give them a chance,
+ * because we need the metadata page their going to
+ * write.
+ */
+ if (!LF_ISSET(DB_CREATE) && retry_cnt++ < 3) {
+ __db_sleep(1, 0);
+ goto open_retry;
+ }
+ if (type == DB_UNKNOWN) {
+ __db_err(dbenv,
+ "%s: DBTYPE of unknown with empty file",
+ fname);
+ goto einval;
+ }
+ goto empty;
+ }
+
+ /*
+ * A found file overrides some user information. We'll check
+ * for possible error conditions based on conflicts between
+ * the file and the user's arguments below.
+ */
+ swapped = 0;
+ F_CLR(dbp, DB_AM_SWAP);
+
+retry: switch (((BTMETA *)mbuf)->magic) {
+ case DB_BTREEMAGIC:
+ if (type != DB_BTREE &&
+ type != DB_RECNO && type != DB_UNKNOWN)
+ goto einval;
+
+ btm = (BTMETA *)mbuf;
+ if (swapped && (ret = __bam_mswap((PAGE *)btm)) != 0)
+ goto err;
+
+ if (btm->version < DB_BTREEOLDVER ||
+ btm->version > DB_BTREEVERSION) {
+ __db_err(dbenv,
+ "%s: unsupported btree version number %lu",
+ fname, (u_long)btm->version);
+ goto einval;
+ }
+ dbp->pgsize = btm->pagesize;
+ F_CLR(dbp, DB_AM_PGDEF);
+
+ if ((ret = __db_fchk(dbenv,
+ "db_open", btm->flags, BTM_MASK)) != 0)
+ goto err;
+ DBINFO_FCHK(dbp, "DB_DUP",
+ btm->flags, BTM_DUP, DB_AM_DUP);
+ if (F_ISSET(btm, BTM_RECNO)) {
+ DBINFO_FCHK(dbp, "DB_FIXEDLEN",
+ btm->flags, BTM_FIXEDLEN, DB_RE_FIXEDLEN);
+ DBINFO_FCHK(dbp, "DB_RENUMBER",
+ btm->flags, BTM_RENUMBER, DB_RE_RENUMBER);
+ type = DB_RECNO;
+ } else {
+ DBINFO_FCHK(dbp, "DB_RECNUM",
+ btm->flags, BTM_RECNUM, DB_BT_RECNUM);
+ type = DB_BTREE;
+ }
+
+ /* Copy the file's unique id. */
+ need_fileid = 0;
+ memcpy(dbp->lock.fileid, btm->uid, DB_FILE_ID_LEN);
+ break;
+ case DB_HASHMAGIC:
+ if (type != DB_HASH && type != DB_UNKNOWN)
+ goto einval;
+
+ hashm = (HASHHDR *)mbuf;
+ if (swapped && (ret = __ham_mswap((PAGE *)hashm)) != 0)
+ goto err;
+
+ if (hashm->version < DB_HASHOLDVER ||
+ hashm->version > DB_HASHVERSION) {
+ __db_err(dbenv,
+ "%s: unsupported hash version number %lu",
+ fname, hashm->version);
+ goto einval;
+ }
+ dbp->pgsize = hashm->pagesize;
+ F_CLR(dbp, DB_AM_PGDEF);
+
+ if ((ret = __db_fchk(dbenv,
+ "db_open", hashm->flags, DB_HASH_DUP)) != 0)
+ goto err;
+ DBINFO_FCHK(dbp, "DB_DUP",
+ hashm->flags, DB_HASH_DUP, DB_AM_DUP);
+ type = DB_HASH;
+
+ /* Copy the file's unique id. */
+ need_fileid = 0;
+ memcpy(dbp->lock.fileid, hashm->uid, DB_FILE_ID_LEN);
+ break;
+ default:
+ if (swapped) {
+ __db_err(dbenv, "unrecognized file type");
+ goto einval;
+ }
+ M_32_SWAP(((BTMETA *)mbuf)->magic);
+ F_SET(dbp, DB_AM_SWAP);
+
+ swapped = 1;
+ goto retry;
+ }
+ } else {
+ fname = real_name = NULL;
+
+ if (type == DB_UNKNOWN) {
+ __db_err(dbenv,
+ "DBTYPE of unknown without existing file");
+ goto einval;
+ }
+ F_SET(dbp, DB_AM_INMEM);
+ }
+
+empty: /*
+ * By the time we get here we've either set the type or we're taking
+ * it from the user.
+ */
+ dbp->type = type;
+
+ /*
+ * Set the page size to the best value for I/O to this file. Don't
+ * overflow the page offset type. The page size must be db_indx_t
+ * aligned and >= MIN_PAGE_SIZE.
+ *
+ * XXX
+ * Should we be checking for a page size that's not a multiple of 512?
+ */
+ if (dbp->pgsize == 0) {
+ F_SET(dbp, DB_AM_PGDEF);
+ dbp->pgsize = 8 * 1024;
+ }
+ if (dbp->pgsize < DB_MIN_PGSIZE ||
+ dbp->pgsize > DB_MAX_PGSIZE ||
+ dbp->pgsize & (sizeof(db_indx_t) - 1)) {
+ __db_err(dbenv, "illegal page size");
+ goto einval;
+ }
+
+ /*
+ * 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.
+ *
+ * XXX
+ * If the user has a DB_ENV structure, we have to use a temporary
+ * one so that we don't step on their values. If the user doesn't,
+ * we have to create one, and keep it around until the call to the
+ * memp_close() function. This is all so the mpool functions get
+ * the error stuff right.
+ */
+ if (dbenv == NULL || dbenv->mp_info == NULL) {
+ F_SET(dbp, DB_AM_MLOCAL);
+
+ if (dbenv == NULL) {
+ if ((dbp->mp_dbenv =
+ (DB_ENV *)calloc(sizeof(DB_ENV), 1)) == NULL) {
+ ret = ENOMEM;
+ goto err;
+ }
+
+ envp = dbp->mp_dbenv;
+ restore = 0;
+ } else {
+ t_dbenv = *dbenv;
+
+ envp = dbenv;
+ restore = 1;
+ }
+ envp->mp_size = cachesize;
+ F_SET(envp, DB_MPOOL_PRIVATE);
+ if ((ret = memp_open(NULL,
+ DB_CREATE, S_IRUSR | S_IWUSR, envp, &dbp->mp)) != 0)
+ goto err;
+ if (restore)
+ *dbenv = t_dbenv;
+ } else
+ dbp->mp = dbenv->mp_info;
+
+ /* Register DB's pgin/pgout functions. */
+ if ((ret = memp_register(dbp->mp,
+ DB_FTYPE_BTREE, __bam_pgin, __bam_pgout)) != 0)
+ goto err;
+ if ((ret = memp_register(dbp->mp,
+ DB_FTYPE_HASH, __ham_pgin, __ham_pgout)) != 0)
+ goto err;
+
+ /*
+ * If we don't already have one, get a unique file ID. If the file
+ * is a temporary file, then we have to create a unique file ID --
+ * no backing file will be created until the mpool cache is filled
+ * forcing it to go to disk. The created ID must never match any
+ * potential real file ID -- we know it won't because real file IDs
+ * contain a time stamp after the dev/ino pair, and we're simply
+ * storing a 4-byte locker ID.
+ *
+ * XXX
+ * Store the file id in the locker structure -- we can get it from
+ * there as necessary, and it saves having two copies.
+ */
+ if (need_fileid)
+ if (fname == NULL) {
+ memset(dbp->lock.fileid, 0, DB_FILE_ID_LEN);
+ if (F_ISSET(dbp, DB_AM_LOCKING) &&
+ (ret = lock_id(dbenv->lk_info,
+ (u_int32_t *)dbp->lock.fileid)) != 0)
+ goto err;
+ } else
+ if ((ret = __db_fileid(dbenv,
+ real_name, 1, dbp->lock.fileid)) != 0)
+ goto err;
+
+ /* No further use for the real name. */
+ if (real_name != NULL)
+ FREES(real_name);
+ real_name = NULL;
+
+ /*
+ * Open a backing file in the memory pool.
+ *
+ * If we need to process the file's pages on I/O, set the file type.
+ * If it's a hash file, always call pgin and pgout routines. This
+ * means that hash files can never be mapped into process memory. If
+ * it's a btree file and requires swapping, we need to page the file
+ * in and out. This has to be right -- we can't mmap files that are
+ * being paged in and out.
+ */
+ if (type == DB_HASH)
+ ftype = DB_FTYPE_HASH;
+ else
+ ftype = F_ISSET(dbp, DB_AM_SWAP) ? DB_FTYPE_BTREE : 0;
+ pginfo.db_pagesize = dbp->pgsize;
+ pginfo.needswap = F_ISSET(dbp, DB_AM_SWAP);
+ pgcookie.data = &pginfo;
+ pgcookie.size = sizeof(DB_PGINFO);
+
+ if ((ret = memp_fopen(dbp->mp, fname, ftype,
+ F_ISSET(dbp, DB_AM_RDONLY) ? DB_RDONLY : 0, 0, dbp->pgsize,
+ 0, &pgcookie, dbp->lock.fileid, &dbp->mpf)) != 0)
+ goto err;
+
+ /* Get a log file id. */
+ if (F_ISSET(dbp, DB_AM_LOGGING) &&
+ (ret = log_register(dbenv->lg_info,
+ dbp, fname, type, &dbp->log_fileid)) != 0)
+ goto err;
+
+ /*
+ * Get a locker id for this DB, and build the lock cookie: the first
+ * db_pgno_t bytes are the page number, the next N bytes are the file
+ * id.
+ */
+ if (F_ISSET(dbp, DB_AM_LOCKING)) {
+ if ((ret = lock_id(dbenv->lk_info, &dbp->locker)) != 0)
+ goto err;
+ dbp->lock_dbt.size = sizeof(dbp->lock);
+ dbp->lock_dbt.data = &dbp->lock;
+ }
+
+ /* Call the real open function. */
+ switch (type) {
+ case DB_BTREE:
+ if (dbinfo != NULL && (ret = __db_fchk(dbenv,
+ "db_open", dbinfo->flags, DB_RECNUM | DB_DUP)) != 0)
+ goto err;
+ if (dbinfo != NULL && (ret = __db_fcchk(dbenv,
+ "db_open", dbinfo->flags, DB_DUP, DB_RECNUM)) != 0)
+ goto err;
+ if ((ret = __bam_open(dbp, type, dbinfo)) != 0)
+ goto err;
+ break;
+ case DB_HASH:
+ if (dbinfo != NULL && (ret = __db_fchk(dbenv,
+ "db_open", dbinfo->flags, DB_DUP)) != 0)
+ goto err;
+ if ((ret = __ham_open(dbp, dbinfo)) != 0)
+ goto err;
+ break;
+ case DB_RECNO:
+#define DB_INFO_FLAGS \
+ (DB_DELIMITER | DB_FIXEDLEN | DB_PAD | DB_RENUMBER | DB_SNAPSHOT)
+ if (dbinfo != NULL && (ret = __db_fchk(dbenv,
+ "db_open", dbinfo->flags, DB_INFO_FLAGS)) != 0)
+ goto err;
+ if ((ret = __ram_open(dbp, type, dbinfo)) != 0)
+ goto err;
+ break;
+ default:
+ abort();
+ }
+
+ /* Call a local close routine. */
+ dbp->close = db_close;
+ dbp->fd = db_fd;
+
+ *dbpp = dbp;
+ return (0);
+
+einval: ret = EINVAL;
+err: /* Close the file descriptor. */
+ if (fd != -1)
+ (void)__db_close(fd);
+
+ /* Discard the log file id. */
+ if (dbp->log_fileid != 0)
+ (void)log_unregister(dbenv->lg_info, dbp->log_fileid);
+
+ /* Close the memory pool file. */
+ if (dbp->mpf != NULL)
+ (void)memp_fclose(dbp->mpf);
+
+ /* If the memory pool was local, close it. */
+ if (F_ISSET(dbp, DB_AM_MLOCAL) && dbp->mp != NULL)
+ (void)memp_close(dbp->mp);
+
+ /* If we allocated a DB_ENV, discard it. */
+ if (dbp->mp_dbenv != NULL)
+ FREE(dbp->mp_dbenv, sizeof(DB_ENV));
+
+ if (real_name != NULL)
+ FREES(real_name);
+ if (dbp != NULL)
+ FREE(dbp, sizeof(DB));
+
+ return (ret);
+}
+
+/*
+ * db_close --
+ * Close a DB tree.
+ */
+static int
+db_close(dbp, flags)
+ DB *dbp;
+ int flags;
+{
+ DBC *dbc;
+ DB *tdbp;
+ int ret, t_ret;
+
+ ret = 0;
+
+ /* Sync the underlying file. */
+ if (!LF_ISSET(DB_NOSYNC) &&
+ (t_ret = dbp->sync(dbp, 0)) != 0 && ret == 0)
+ ret = t_ret;
+
+ /*
+ * Call the underlying access method close routine for all the
+ * cursors and handles.
+ */
+ for (tdbp = LIST_FIRST(&dbp->handleq);
+ tdbp != NULL; tdbp = LIST_NEXT(tdbp, links)) {
+
+ while ((dbc = TAILQ_FIRST(&tdbp->curs_queue)) != NULL)
+ if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0)
+ ret = t_ret;
+
+ switch (tdbp->type) {
+ case DB_BTREE:
+ if ((t_ret = __bam_close(tdbp)) != 0 && ret == 0)
+ ret = t_ret;
+ break;
+ case DB_HASH:
+ if ((t_ret = __ham_close(tdbp)) != 0 && ret == 0)
+ ret = t_ret;
+ break;
+ case DB_RECNO:
+ if ((t_ret = __ram_close(tdbp)) != 0 && ret == 0)
+ ret = t_ret;
+ break;
+ default:
+ abort();
+ }
+
+ }
+
+ /* Sync the memory pool. */
+ if ((t_ret = memp_fsync(dbp->mpf)) != 0 && ret == 0)
+ ret = t_ret;
+
+ /* Close the memory pool file. */
+ if ((t_ret = memp_fclose(dbp->mpf)) != 0 && ret == 0)
+ ret = t_ret;
+
+ /* If the memory pool was local, close it. */
+ if (F_ISSET(dbp, DB_AM_MLOCAL) &&
+ (t_ret = memp_close(dbp->mp)) != 0 && ret == 0)
+ ret = t_ret;
+
+ /* Discard the mutex. */
+ if (dbp->mutex != NULL)
+ FREE(dbp->mutex, sizeof(db_mutex_t));
+
+ /* Discard the log file id. */
+ if (F_ISSET(dbp, DB_AM_LOGGING))
+ (void)log_unregister(dbp->dbenv->lg_info, dbp->log_fileid);
+
+ /* Discard the lock cookie for all handles. */
+ for (tdbp = LIST_FIRST(&dbp->handleq);
+ tdbp != NULL; tdbp = LIST_NEXT(tdbp, links))
+ if (F_ISSET(tdbp, DB_AM_LOCKING)) {
+#ifdef DEBUG
+ DB_LOCKREQ request;
+
+ /*
+ * If we're running tests, display any locks currently
+ * held. It's possible that some applications may hold
+ * locks for long periods, e.g., conference room locks,
+ * but the DB tests should never close holding locks.
+ */
+ request.op = DB_LOCK_DUMP;
+ if ((t_ret = lock_vec(tdbp->dbenv->lk_info,
+ tdbp->locker, 0, &request, 1, NULL)) != 0 &&
+ ret == 0)
+ ret = EAGAIN;
+#endif
+ }
+
+ /* If we allocated a DB_ENV, discard it. */
+ if (dbp->mp_dbenv != NULL)
+ FREE(dbp->mp_dbenv, sizeof(DB_ENV));
+
+ /* Free all of the DB's. */
+ LIST_REMOVE(dbp, links);
+ while ((tdbp = LIST_FIRST(&dbp->handleq)) != NULL) {
+ LIST_REMOVE(tdbp, links);
+ FREE(tdbp, sizeof(*tdbp));
+ }
+ FREE(dbp, sizeof(*dbp));
+
+ return (ret);
+}
+
+/*
+ * db_fd --
+ * Return a file descriptor for flock'ing.
+ */
+static int
+db_fd(dbp, fdp)
+ DB *dbp;
+ int *fdp;
+{
+ /* In-memory database can't have a file descriptor. */
+ if (F_ISSET(dbp, DB_AM_INMEM))
+ return (ENOENT);
+
+ /*
+ * XXX
+ * Truly spectacular layering violation. As we don't open the
+ * underlying file until we need it, it may not be initialized.
+ */
+ if ((*fdp = dbp->mpf->fd) == -1)
+ return (ENOENT);
+ return (0);
+}
+
+/*
+ * __db_pgerr --
+ * Error when unable to retrieve a specified page.
+ *
+ * PUBLIC: int __db_pgerr __P((DB *, db_pgno_t));
+ */
+int
+__db_pgerr(dbp, pgno)
+ DB *dbp;
+ db_pgno_t pgno;
+{
+ __db_err(dbp->dbenv,
+ "unable to create/retrieve page %lu", (u_long)pgno);
+ return (__db_panic(dbp));
+}
+
+/*
+ * __db_pgfmt --
+ * Error when a page has the wrong format.
+ *
+ * PUBLIC: int __db_pgfmt __P((DB *, db_pgno_t));
+ */
+int
+__db_pgfmt(dbp, pgno)
+ DB *dbp;
+ db_pgno_t pgno;
+{
+ __db_err(dbp->dbenv,
+ "page %lu: illegal page type or format", (u_long)pgno);
+ return (__db_panic(dbp));
+}
diff --git a/db2/db/db.src b/db2/db/db.src
new file mode 100644
index 0000000000..a3e2f7b75c
--- /dev/null
+++ b/db2/db/db.src
@@ -0,0 +1,154 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1996, 1997
+ * Sleepycat Software. All rights reserved.
+ * @(#)db.src 10.3 (Sleepycat) 8/18/97
+ */
+#include "config.h"
+
+PREFIX db
+
+/*
+ * addrem -- Add or remove an entry from a duplicate page.
+ *
+ * opcode: identifies if this is an add or delete.
+ * fileid: file identifier of the file being modified.
+ * pgno: duplicate page number.
+ * indx: location at which to insert or delete.
+ * nbytes: number of bytes added/removed to/from the page.
+ * hdr: header for the data item.
+ * dbt: data that is deleted or is to be added.
+ * pagelsn: former lsn of the page.
+ *
+ * If the hdr was NULL then, the dbt is a regular B_KEYDATA.
+ * If the dbt was NULL then the hdr is a complete item to be
+ * pasted on the page.
+ */
+BEGIN addrem
+ARG opcode u_int32_t lu
+ARG fileid u_int32_t lu
+ARG pgno db_pgno_t lu
+ARG indx u_int32_t lu
+ARG nbytes size_t lu
+DBT hdr DBT s
+DBT dbt DBT s
+POINTER pagelsn DB_LSN * lu
+END
+
+/*
+ * split -- Handles the split of a duplicate page.
+ *
+ * opcode: defines whether we are splitting from or splitting onto
+ * fileid: file identifier of the file being modified.
+ * pgno: page number being split.
+ * pageimage: entire page contents.
+ * pagelsn: former lsn of the page.
+ */
+BEGIN split
+ARG opcode u_int32_t lu
+ARG fileid u_int32_t lu
+ARG pgno db_pgno_t lu
+DBT pageimage DBT s
+POINTER pagelsn DB_LSN * lu
+END
+
+/*
+ * big -- Handles addition and deletion of big key/data items.
+ *
+ * opcode: identifies get/put.
+ * fileid: file identifier of the file being modified.
+ * pgno: page onto which data is being added/removed.
+ * prev_pgno: the page before the one we are logging.
+ * next_pgno: the page after the one we are logging.
+ * dbt: data being written onto the page.
+ * pagelsn: former lsn of the orig_page.
+ * prevlsn: former lsn of the prev_pgno.
+ * nextlsn: former lsn of the next_pgno. This is not currently used, but
+ * may be used later if we actually do overwrites of big key/
+ * data items in place.
+ */
+BEGIN big
+ARG opcode u_int32_t lu
+ARG fileid u_int32_t lu
+ARG pgno db_pgno_t lu
+ARG prev_pgno db_pgno_t lu
+ARG next_pgno db_pgno_t lu
+DBT dbt DBT s
+POINTER pagelsn DB_LSN * lu
+POINTER prevlsn DB_LSN * lu
+POINTER nextlsn DB_LSN * lu
+END
+
+/*
+ * ovref -- Handles increment of overflow page reference count.
+ *
+ * fileid: identifies the file being modified.
+ * pgno: page number being incremented.
+ * lsn the page's original lsn.
+ */
+BEGIN ovref
+ARG fileid u_int32_t lu
+ARG pgno db_pgno_t lu
+POINTER lsn DB_LSN * lu
+END
+
+/*
+ * relink -- Handles relinking around a page.
+ *
+ * pgno: the page being changed.
+ * lsn the page's original lsn.
+ * prev: the previous page.
+ * lsn_prev: the previous page's original lsn.
+ * next: the next page.
+ * lsn_next: the previous page's original lsn.
+ */
+BEGIN relink
+ARG fileid u_int32_t lu
+ARG pgno db_pgno_t lu
+POINTER lsn DB_LSN * lu
+ARG prev db_pgno_t lu
+POINTER lsn_prev DB_LSN * lu
+ARG next db_pgno_t lu
+POINTER lsn_next DB_LSN * lu
+END
+
+/*
+ * Addpage -- Handles adding a new duplicate page onto the end of
+ * an existing duplicate page.
+ * fileid: identifies the file being changed.
+ * pgno: page number to which a new page is being added.
+ * lsn: lsn of pgno
+ * nextpgno: new page number being added.
+ * nextlsn: lsn of nextpgno;
+ */
+BEGIN addpage
+ARG fileid u_int32_t lu
+ARG pgno db_pgno_t lu
+POINTER lsn DB_LSN * lu
+ARG nextpgno db_pgno_t lu
+POINTER nextlsn DB_LSN * lu
+END
+
+/*
+ * Debug -- log an operation upon entering an access method.
+ * op: Operation (cursor, c_close, c_get, c_put, c_del,
+ * get, put, delete).
+ * fileid: identifies the file being acted upon.
+ * key: key paramater
+ * data: data parameter
+ * flags: flags parameter
+ */
+BEGIN debug
+DBT op DBT s
+ARG fileid u_int32_t lu
+DBT key DBT s
+DBT data DBT s
+ARG arg_flags u_int32_t lu
+END
+
+/*
+ * noop -- do nothing, but get an LSN.
+ */
+BEGIN noop
+END
diff --git a/db2/db/db_auto.c b/db2/db/db_auto.c
new file mode 100644
index 0000000000..4684f1a39f
--- /dev/null
+++ b/db2/db/db_auto.c
@@ -0,0 +1,1462 @@
+/* Do not edit: automatically built by dist/db_gen.sh. */
+#include "config.h"
+
+#ifndef NO_SYSTEM_INCLUDES
+#include <ctype.h>
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#endif
+
+#include "db_int.h"
+#include "shqueue.h"
+#include "db_page.h"
+#include "db_dispatch.h"
+#include "db_am.h"
+#include "common_ext.h"
+
+/*
+ * PUBLIC: int __db_addrem_log
+ * PUBLIC: __P((DB_LOG *, DB_TXN *, DB_LSN *, u_int32_t,
+ * PUBLIC: u_int32_t, u_int32_t, db_pgno_t, u_int32_t,
+ * PUBLIC: size_t, DBT *, DBT *, DB_LSN *));
+ */
+int __db_addrem_log(logp, txnid, ret_lsnp, flags,
+ opcode, fileid, pgno, indx, nbytes, hdr,
+ dbt, pagelsn)
+ DB_LOG *logp;
+ DB_TXN *txnid;
+ DB_LSN *ret_lsnp;
+ u_int32_t flags;
+ u_int32_t opcode;
+ u_int32_t fileid;
+ db_pgno_t pgno;
+ u_int32_t indx;
+ size_t nbytes;
+ DBT *hdr;
+ DBT *dbt;
+ DB_LSN * pagelsn;
+{
+ DBT logrec;
+ DB_LSN *lsnp, null_lsn;
+ u_int32_t zero;
+ u_int32_t rectype, txn_num;
+ int ret;
+ u_int8_t *bp;
+
+ rectype = DB_db_addrem;
+ txn_num = txnid == NULL ? 0 : txnid->txnid;
+ if (txnid == NULL) {
+ null_lsn.file = 0;
+ null_lsn.offset = 0;
+ lsnp = &null_lsn;
+ } else
+ lsnp = &txnid->last_lsn;
+ logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN)
+ + sizeof(opcode)
+ + sizeof(fileid)
+ + sizeof(pgno)
+ + sizeof(indx)
+ + sizeof(nbytes)
+ + sizeof(u_int32_t) + (hdr == NULL ? 0 : hdr->size)
+ + sizeof(u_int32_t) + (dbt == NULL ? 0 : dbt->size)
+ + sizeof(*pagelsn);
+ if ((logrec.data = (void *)malloc(logrec.size)) == NULL)
+ return (ENOMEM);
+
+ bp = logrec.data;
+ memcpy(bp, &rectype, sizeof(rectype));
+ bp += sizeof(rectype);
+ memcpy(bp, &txn_num, sizeof(txn_num));
+ bp += sizeof(txn_num);
+ memcpy(bp, lsnp, sizeof(DB_LSN));
+ bp += sizeof(DB_LSN);
+ memcpy(bp, &opcode, sizeof(opcode));
+ bp += sizeof(opcode);
+ memcpy(bp, &fileid, sizeof(fileid));
+ bp += sizeof(fileid);
+ memcpy(bp, &pgno, sizeof(pgno));
+ bp += sizeof(pgno);
+ memcpy(bp, &indx, sizeof(indx));
+ bp += sizeof(indx);
+ memcpy(bp, &nbytes, sizeof(nbytes));
+ bp += sizeof(nbytes);
+ if (hdr == NULL) {
+ zero = 0;
+ memcpy(bp, &zero, sizeof(u_int32_t));
+ bp += sizeof(u_int32_t);
+ } else {
+ memcpy(bp, &hdr->size, sizeof(hdr->size));
+ bp += sizeof(hdr->size);
+ memcpy(bp, hdr->data, hdr->size);
+ bp += hdr->size;
+ }
+ if (dbt == NULL) {
+ zero = 0;
+ memcpy(bp, &zero, sizeof(u_int32_t));
+ bp += sizeof(u_int32_t);
+ } else {
+ memcpy(bp, &dbt->size, sizeof(dbt->size));
+ bp += sizeof(dbt->size);
+ memcpy(bp, dbt->data, dbt->size);
+ bp += dbt->size;
+ }
+ if (pagelsn != NULL)
+ memcpy(bp, pagelsn, sizeof(*pagelsn));
+ else
+ memset(bp, 0, sizeof(*pagelsn));
+ bp += sizeof(*pagelsn);
+#ifdef DEBUG
+ if ((u_int32_t)(bp - (u_int8_t *)logrec.data) != logrec.size)
+ fprintf(stderr, "Error in log record length");
+#endif
+ ret = log_put(logp, ret_lsnp, (DBT *)&logrec, flags);
+ if (txnid != NULL)
+ txnid->last_lsn = *ret_lsnp;
+ free(logrec.data);
+ return (ret);
+}
+
+/*
+ * PUBLIC: int __db_addrem_print
+ * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
+ */
+
+int
+__db_addrem_print(notused1, dbtp, lsnp, notused3, notused4)
+ DB_LOG *notused1;
+ DBT *dbtp;
+ DB_LSN *lsnp;
+ int notused3;
+ void *notused4;
+{
+ __db_addrem_args *argp;
+ u_int32_t i;
+ int c, ret;
+
+ i = 0;
+ c = 0;
+ notused1 = NULL;
+ notused3 = 0;
+ notused4 = NULL;
+
+ if((ret = __db_addrem_read(dbtp->data, &argp)) != 0)
+ return (ret);
+ printf("[%lu][%lu]db_addrem: rec: %lu txnid %lx prevlsn [%lu][%lu]\n",
+ (u_long)lsnp->file,
+ (u_long)lsnp->offset,
+ (u_long)argp->type,
+ (u_long)argp->txnid->txnid,
+ (u_long)argp->prev_lsn.file,
+ (u_long)argp->prev_lsn.offset);
+ printf("\topcode: %lu\n", (u_long)argp->opcode);
+ printf("\tfileid: %lu\n", (u_long)argp->fileid);
+ printf("\tpgno: %lu\n", (u_long)argp->pgno);
+ printf("\tindx: %lu\n", (u_long)argp->indx);
+ printf("\tnbytes: %lu\n", (u_long)argp->nbytes);
+ printf("\thdr: ");
+ for (i = 0; i < argp->hdr.size; i++) {
+ c = ((char *)argp->hdr.data)[i];
+ if (isprint(c) || c == 0xa)
+ putchar(c);
+ else
+ printf("%#x ", c);
+ }
+ printf("\n");
+ printf("\tdbt: ");
+ for (i = 0; i < argp->dbt.size; i++) {
+ c = ((char *)argp->dbt.data)[i];
+ if (isprint(c) || c == 0xa)
+ putchar(c);
+ else
+ printf("%#x ", c);
+ }
+ printf("\n");
+ printf("\tpagelsn: [%lu][%lu]\n",
+ (u_long)argp->pagelsn.file, (u_long)argp->pagelsn.offset);
+ printf("\n");
+ free(argp);
+ return (0);
+}
+
+/*
+ * PUBLIC: int __db_addrem_read __P((void *, __db_addrem_args **));
+ */
+int
+__db_addrem_read(recbuf, argpp)
+ void *recbuf;
+ __db_addrem_args **argpp;
+{
+ __db_addrem_args *argp;
+ u_int8_t *bp;
+
+ argp = (__db_addrem_args *)malloc(sizeof(__db_addrem_args) +
+ sizeof(DB_TXN));
+ if (argp == NULL)
+ return (ENOMEM);
+ argp->txnid = (DB_TXN *)&argp[1];
+ bp = recbuf;
+ memcpy(&argp->type, bp, sizeof(argp->type));
+ bp += sizeof(argp->type);
+ memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid));
+ bp += sizeof(argp->txnid->txnid);
+ memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN));
+ bp += sizeof(DB_LSN);
+ memcpy(&argp->opcode, bp, sizeof(argp->opcode));
+ bp += sizeof(argp->opcode);
+ memcpy(&argp->fileid, bp, sizeof(argp->fileid));
+ bp += sizeof(argp->fileid);
+ memcpy(&argp->pgno, bp, sizeof(argp->pgno));
+ bp += sizeof(argp->pgno);
+ memcpy(&argp->indx, bp, sizeof(argp->indx));
+ bp += sizeof(argp->indx);
+ memcpy(&argp->nbytes, bp, sizeof(argp->nbytes));
+ bp += sizeof(argp->nbytes);
+ memcpy(&argp->hdr.size, bp, sizeof(u_int32_t));
+ bp += sizeof(u_int32_t);
+ argp->hdr.data = bp;
+ bp += argp->hdr.size;
+ memcpy(&argp->dbt.size, bp, sizeof(u_int32_t));
+ bp += sizeof(u_int32_t);
+ argp->dbt.data = bp;
+ bp += argp->dbt.size;
+ memcpy(&argp->pagelsn, bp, sizeof(argp->pagelsn));
+ bp += sizeof(argp->pagelsn);
+ *argpp = argp;
+ return (0);
+}
+
+/*
+ * PUBLIC: int __db_split_log
+ * PUBLIC: __P((DB_LOG *, DB_TXN *, DB_LSN *, u_int32_t,
+ * PUBLIC: u_int32_t, u_int32_t, db_pgno_t, DBT *,
+ * PUBLIC: DB_LSN *));
+ */
+int __db_split_log(logp, txnid, ret_lsnp, flags,
+ opcode, fileid, pgno, pageimage, pagelsn)
+ DB_LOG *logp;
+ DB_TXN *txnid;
+ DB_LSN *ret_lsnp;
+ u_int32_t flags;
+ u_int32_t opcode;
+ u_int32_t fileid;
+ db_pgno_t pgno;
+ DBT *pageimage;
+ DB_LSN * pagelsn;
+{
+ DBT logrec;
+ DB_LSN *lsnp, null_lsn;
+ u_int32_t zero;
+ u_int32_t rectype, txn_num;
+ int ret;
+ u_int8_t *bp;
+
+ rectype = DB_db_split;
+ txn_num = txnid == NULL ? 0 : txnid->txnid;
+ if (txnid == NULL) {
+ null_lsn.file = 0;
+ null_lsn.offset = 0;
+ lsnp = &null_lsn;
+ } else
+ lsnp = &txnid->last_lsn;
+ logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN)
+ + sizeof(opcode)
+ + sizeof(fileid)
+ + sizeof(pgno)
+ + sizeof(u_int32_t) + (pageimage == NULL ? 0 : pageimage->size)
+ + sizeof(*pagelsn);
+ if ((logrec.data = (void *)malloc(logrec.size)) == NULL)
+ return (ENOMEM);
+
+ bp = logrec.data;
+ memcpy(bp, &rectype, sizeof(rectype));
+ bp += sizeof(rectype);
+ memcpy(bp, &txn_num, sizeof(txn_num));
+ bp += sizeof(txn_num);
+ memcpy(bp, lsnp, sizeof(DB_LSN));
+ bp += sizeof(DB_LSN);
+ memcpy(bp, &opcode, sizeof(opcode));
+ bp += sizeof(opcode);
+ memcpy(bp, &fileid, sizeof(fileid));
+ bp += sizeof(fileid);
+ memcpy(bp, &pgno, sizeof(pgno));
+ bp += sizeof(pgno);
+ if (pageimage == NULL) {
+ zero = 0;
+ memcpy(bp, &zero, sizeof(u_int32_t));
+ bp += sizeof(u_int32_t);
+ } else {
+ memcpy(bp, &pageimage->size, sizeof(pageimage->size));
+ bp += sizeof(pageimage->size);
+ memcpy(bp, pageimage->data, pageimage->size);
+ bp += pageimage->size;
+ }
+ if (pagelsn != NULL)
+ memcpy(bp, pagelsn, sizeof(*pagelsn));
+ else
+ memset(bp, 0, sizeof(*pagelsn));
+ bp += sizeof(*pagelsn);
+#ifdef DEBUG
+ if ((u_int32_t)(bp - (u_int8_t *)logrec.data) != logrec.size)
+ fprintf(stderr, "Error in log record length");
+#endif
+ ret = log_put(logp, ret_lsnp, (DBT *)&logrec, flags);
+ if (txnid != NULL)
+ txnid->last_lsn = *ret_lsnp;
+ free(logrec.data);
+ return (ret);
+}
+
+/*
+ * PUBLIC: int __db_split_print
+ * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
+ */
+
+int
+__db_split_print(notused1, dbtp, lsnp, notused3, notused4)
+ DB_LOG *notused1;
+ DBT *dbtp;
+ DB_LSN *lsnp;
+ int notused3;
+ void *notused4;
+{
+ __db_split_args *argp;
+ u_int32_t i;
+ int c, ret;
+
+ i = 0;
+ c = 0;
+ notused1 = NULL;
+ notused3 = 0;
+ notused4 = NULL;
+
+ if((ret = __db_split_read(dbtp->data, &argp)) != 0)
+ return (ret);
+ printf("[%lu][%lu]db_split: rec: %lu txnid %lx prevlsn [%lu][%lu]\n",
+ (u_long)lsnp->file,
+ (u_long)lsnp->offset,
+ (u_long)argp->type,
+ (u_long)argp->txnid->txnid,
+ (u_long)argp->prev_lsn.file,
+ (u_long)argp->prev_lsn.offset);
+ printf("\topcode: %lu\n", (u_long)argp->opcode);
+ printf("\tfileid: %lu\n", (u_long)argp->fileid);
+ printf("\tpgno: %lu\n", (u_long)argp->pgno);
+ printf("\tpageimage: ");
+ for (i = 0; i < argp->pageimage.size; i++) {
+ c = ((char *)argp->pageimage.data)[i];
+ if (isprint(c) || c == 0xa)
+ putchar(c);
+ else
+ printf("%#x ", c);
+ }
+ printf("\n");
+ printf("\tpagelsn: [%lu][%lu]\n",
+ (u_long)argp->pagelsn.file, (u_long)argp->pagelsn.offset);
+ printf("\n");
+ free(argp);
+ return (0);
+}
+
+/*
+ * PUBLIC: int __db_split_read __P((void *, __db_split_args **));
+ */
+int
+__db_split_read(recbuf, argpp)
+ void *recbuf;
+ __db_split_args **argpp;
+{
+ __db_split_args *argp;
+ u_int8_t *bp;
+
+ argp = (__db_split_args *)malloc(sizeof(__db_split_args) +
+ sizeof(DB_TXN));
+ if (argp == NULL)
+ return (ENOMEM);
+ argp->txnid = (DB_TXN *)&argp[1];
+ bp = recbuf;
+ memcpy(&argp->type, bp, sizeof(argp->type));
+ bp += sizeof(argp->type);
+ memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid));
+ bp += sizeof(argp->txnid->txnid);
+ memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN));
+ bp += sizeof(DB_LSN);
+ memcpy(&argp->opcode, bp, sizeof(argp->opcode));
+ bp += sizeof(argp->opcode);
+ memcpy(&argp->fileid, bp, sizeof(argp->fileid));
+ bp += sizeof(argp->fileid);
+ memcpy(&argp->pgno, bp, sizeof(argp->pgno));
+ bp += sizeof(argp->pgno);
+ memcpy(&argp->pageimage.size, bp, sizeof(u_int32_t));
+ bp += sizeof(u_int32_t);
+ argp->pageimage.data = bp;
+ bp += argp->pageimage.size;
+ memcpy(&argp->pagelsn, bp, sizeof(argp->pagelsn));
+ bp += sizeof(argp->pagelsn);
+ *argpp = argp;
+ return (0);
+}
+
+/*
+ * PUBLIC: int __db_big_log
+ * PUBLIC: __P((DB_LOG *, DB_TXN *, DB_LSN *, u_int32_t,
+ * PUBLIC: u_int32_t, u_int32_t, db_pgno_t, db_pgno_t,
+ * PUBLIC: db_pgno_t, DBT *, DB_LSN *, DB_LSN *,
+ * PUBLIC: DB_LSN *));
+ */
+int __db_big_log(logp, txnid, ret_lsnp, flags,
+ opcode, fileid, pgno, prev_pgno, next_pgno, dbt,
+ pagelsn, prevlsn, nextlsn)
+ DB_LOG *logp;
+ DB_TXN *txnid;
+ DB_LSN *ret_lsnp;
+ u_int32_t flags;
+ u_int32_t opcode;
+ u_int32_t fileid;
+ db_pgno_t pgno;
+ db_pgno_t prev_pgno;
+ db_pgno_t next_pgno;
+ DBT *dbt;
+ DB_LSN * pagelsn;
+ DB_LSN * prevlsn;
+ DB_LSN * nextlsn;
+{
+ DBT logrec;
+ DB_LSN *lsnp, null_lsn;
+ u_int32_t zero;
+ u_int32_t rectype, txn_num;
+ int ret;
+ u_int8_t *bp;
+
+ rectype = DB_db_big;
+ txn_num = txnid == NULL ? 0 : txnid->txnid;
+ if (txnid == NULL) {
+ null_lsn.file = 0;
+ null_lsn.offset = 0;
+ lsnp = &null_lsn;
+ } else
+ lsnp = &txnid->last_lsn;
+ logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN)
+ + sizeof(opcode)
+ + sizeof(fileid)
+ + sizeof(pgno)
+ + sizeof(prev_pgno)
+ + sizeof(next_pgno)
+ + sizeof(u_int32_t) + (dbt == NULL ? 0 : dbt->size)
+ + sizeof(*pagelsn)
+ + sizeof(*prevlsn)
+ + sizeof(*nextlsn);
+ if ((logrec.data = (void *)malloc(logrec.size)) == NULL)
+ return (ENOMEM);
+
+ bp = logrec.data;
+ memcpy(bp, &rectype, sizeof(rectype));
+ bp += sizeof(rectype);
+ memcpy(bp, &txn_num, sizeof(txn_num));
+ bp += sizeof(txn_num);
+ memcpy(bp, lsnp, sizeof(DB_LSN));
+ bp += sizeof(DB_LSN);
+ memcpy(bp, &opcode, sizeof(opcode));
+ bp += sizeof(opcode);
+ memcpy(bp, &fileid, sizeof(fileid));
+ bp += sizeof(fileid);
+ memcpy(bp, &pgno, sizeof(pgno));
+ bp += sizeof(pgno);
+ memcpy(bp, &prev_pgno, sizeof(prev_pgno));
+ bp += sizeof(prev_pgno);
+ memcpy(bp, &next_pgno, sizeof(next_pgno));
+ bp += sizeof(next_pgno);
+ if (dbt == NULL) {
+ zero = 0;
+ memcpy(bp, &zero, sizeof(u_int32_t));
+ bp += sizeof(u_int32_t);
+ } else {
+ memcpy(bp, &dbt->size, sizeof(dbt->size));
+ bp += sizeof(dbt->size);
+ memcpy(bp, dbt->data, dbt->size);
+ bp += dbt->size;
+ }
+ if (pagelsn != NULL)
+ memcpy(bp, pagelsn, sizeof(*pagelsn));
+ else
+ memset(bp, 0, sizeof(*pagelsn));
+ bp += sizeof(*pagelsn);
+ if (prevlsn != NULL)
+ memcpy(bp, prevlsn, sizeof(*prevlsn));
+ else
+ memset(bp, 0, sizeof(*prevlsn));
+ bp += sizeof(*prevlsn);
+ if (nextlsn != NULL)
+ memcpy(bp, nextlsn, sizeof(*nextlsn));
+ else
+ memset(bp, 0, sizeof(*nextlsn));
+ bp += sizeof(*nextlsn);
+#ifdef DEBUG
+ if ((u_int32_t)(bp - (u_int8_t *)logrec.data) != logrec.size)
+ fprintf(stderr, "Error in log record length");
+#endif
+ ret = log_put(logp, ret_lsnp, (DBT *)&logrec, flags);
+ if (txnid != NULL)
+ txnid->last_lsn = *ret_lsnp;
+ free(logrec.data);
+ return (ret);
+}
+
+/*
+ * PUBLIC: int __db_big_print
+ * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
+ */
+
+int
+__db_big_print(notused1, dbtp, lsnp, notused3, notused4)
+ DB_LOG *notused1;
+ DBT *dbtp;
+ DB_LSN *lsnp;
+ int notused3;
+ void *notused4;
+{
+ __db_big_args *argp;
+ u_int32_t i;
+ int c, ret;
+
+ i = 0;
+ c = 0;
+ notused1 = NULL;
+ notused3 = 0;
+ notused4 = NULL;
+
+ if((ret = __db_big_read(dbtp->data, &argp)) != 0)
+ return (ret);
+ printf("[%lu][%lu]db_big: rec: %lu txnid %lx prevlsn [%lu][%lu]\n",
+ (u_long)lsnp->file,
+ (u_long)lsnp->offset,
+ (u_long)argp->type,
+ (u_long)argp->txnid->txnid,
+ (u_long)argp->prev_lsn.file,
+ (u_long)argp->prev_lsn.offset);
+ printf("\topcode: %lu\n", (u_long)argp->opcode);
+ printf("\tfileid: %lu\n", (u_long)argp->fileid);
+ printf("\tpgno: %lu\n", (u_long)argp->pgno);
+ printf("\tprev_pgno: %lu\n", (u_long)argp->prev_pgno);
+ printf("\tnext_pgno: %lu\n", (u_long)argp->next_pgno);
+ printf("\tdbt: ");
+ for (i = 0; i < argp->dbt.size; i++) {
+ c = ((char *)argp->dbt.data)[i];
+ if (isprint(c) || c == 0xa)
+ putchar(c);
+ else
+ printf("%#x ", c);
+ }
+ printf("\n");
+ printf("\tpagelsn: [%lu][%lu]\n",
+ (u_long)argp->pagelsn.file, (u_long)argp->pagelsn.offset);
+ printf("\tprevlsn: [%lu][%lu]\n",
+ (u_long)argp->prevlsn.file, (u_long)argp->prevlsn.offset);
+ printf("\tnextlsn: [%lu][%lu]\n",
+ (u_long)argp->nextlsn.file, (u_long)argp->nextlsn.offset);
+ printf("\n");
+ free(argp);
+ return (0);
+}
+
+/*
+ * PUBLIC: int __db_big_read __P((void *, __db_big_args **));
+ */
+int
+__db_big_read(recbuf, argpp)
+ void *recbuf;
+ __db_big_args **argpp;
+{
+ __db_big_args *argp;
+ u_int8_t *bp;
+
+ argp = (__db_big_args *)malloc(sizeof(__db_big_args) +
+ sizeof(DB_TXN));
+ if (argp == NULL)
+ return (ENOMEM);
+ argp->txnid = (DB_TXN *)&argp[1];
+ bp = recbuf;
+ memcpy(&argp->type, bp, sizeof(argp->type));
+ bp += sizeof(argp->type);
+ memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid));
+ bp += sizeof(argp->txnid->txnid);
+ memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN));
+ bp += sizeof(DB_LSN);
+ memcpy(&argp->opcode, bp, sizeof(argp->opcode));
+ bp += sizeof(argp->opcode);
+ memcpy(&argp->fileid, bp, sizeof(argp->fileid));
+ bp += sizeof(argp->fileid);
+ memcpy(&argp->pgno, bp, sizeof(argp->pgno));
+ bp += sizeof(argp->pgno);
+ memcpy(&argp->prev_pgno, bp, sizeof(argp->prev_pgno));
+ bp += sizeof(argp->prev_pgno);
+ memcpy(&argp->next_pgno, bp, sizeof(argp->next_pgno));
+ bp += sizeof(argp->next_pgno);
+ memcpy(&argp->dbt.size, bp, sizeof(u_int32_t));
+ bp += sizeof(u_int32_t);
+ argp->dbt.data = bp;
+ bp += argp->dbt.size;
+ memcpy(&argp->pagelsn, bp, sizeof(argp->pagelsn));
+ bp += sizeof(argp->pagelsn);
+ memcpy(&argp->prevlsn, bp, sizeof(argp->prevlsn));
+ bp += sizeof(argp->prevlsn);
+ memcpy(&argp->nextlsn, bp, sizeof(argp->nextlsn));
+ bp += sizeof(argp->nextlsn);
+ *argpp = argp;
+ return (0);
+}
+
+/*
+ * PUBLIC: int __db_ovref_log
+ * PUBLIC: __P((DB_LOG *, DB_TXN *, DB_LSN *, u_int32_t,
+ * PUBLIC: u_int32_t, db_pgno_t, DB_LSN *));
+ */
+int __db_ovref_log(logp, txnid, ret_lsnp, flags,
+ fileid, pgno, lsn)
+ DB_LOG *logp;
+ DB_TXN *txnid;
+ DB_LSN *ret_lsnp;
+ u_int32_t flags;
+ u_int32_t fileid;
+ db_pgno_t pgno;
+ DB_LSN * lsn;
+{
+ DBT logrec;
+ DB_LSN *lsnp, null_lsn;
+ u_int32_t rectype, txn_num;
+ int ret;
+ u_int8_t *bp;
+
+ rectype = DB_db_ovref;
+ txn_num = txnid == NULL ? 0 : txnid->txnid;
+ if (txnid == NULL) {
+ null_lsn.file = 0;
+ null_lsn.offset = 0;
+ lsnp = &null_lsn;
+ } else
+ lsnp = &txnid->last_lsn;
+ logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN)
+ + sizeof(fileid)
+ + sizeof(pgno)
+ + sizeof(*lsn);
+ if ((logrec.data = (void *)malloc(logrec.size)) == NULL)
+ return (ENOMEM);
+
+ bp = logrec.data;
+ memcpy(bp, &rectype, sizeof(rectype));
+ bp += sizeof(rectype);
+ memcpy(bp, &txn_num, sizeof(txn_num));
+ bp += sizeof(txn_num);
+ memcpy(bp, lsnp, sizeof(DB_LSN));
+ bp += sizeof(DB_LSN);
+ memcpy(bp, &fileid, sizeof(fileid));
+ bp += sizeof(fileid);
+ memcpy(bp, &pgno, sizeof(pgno));
+ bp += sizeof(pgno);
+ if (lsn != NULL)
+ memcpy(bp, lsn, sizeof(*lsn));
+ else
+ memset(bp, 0, sizeof(*lsn));
+ bp += sizeof(*lsn);
+#ifdef DEBUG
+ if ((u_int32_t)(bp - (u_int8_t *)logrec.data) != logrec.size)
+ fprintf(stderr, "Error in log record length");
+#endif
+ ret = log_put(logp, ret_lsnp, (DBT *)&logrec, flags);
+ if (txnid != NULL)
+ txnid->last_lsn = *ret_lsnp;
+ free(logrec.data);
+ return (ret);
+}
+
+/*
+ * PUBLIC: int __db_ovref_print
+ * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
+ */
+
+int
+__db_ovref_print(notused1, dbtp, lsnp, notused3, notused4)
+ DB_LOG *notused1;
+ DBT *dbtp;
+ DB_LSN *lsnp;
+ int notused3;
+ void *notused4;
+{
+ __db_ovref_args *argp;
+ u_int32_t i;
+ int c, ret;
+
+ i = 0;
+ c = 0;
+ notused1 = NULL;
+ notused3 = 0;
+ notused4 = NULL;
+
+ if((ret = __db_ovref_read(dbtp->data, &argp)) != 0)
+ return (ret);
+ printf("[%lu][%lu]db_ovref: rec: %lu txnid %lx prevlsn [%lu][%lu]\n",
+ (u_long)lsnp->file,
+ (u_long)lsnp->offset,
+ (u_long)argp->type,
+ (u_long)argp->txnid->txnid,
+ (u_long)argp->prev_lsn.file,
+ (u_long)argp->prev_lsn.offset);
+ printf("\tfileid: %lu\n", (u_long)argp->fileid);
+ printf("\tpgno: %lu\n", (u_long)argp->pgno);
+ printf("\tlsn: [%lu][%lu]\n",
+ (u_long)argp->lsn.file, (u_long)argp->lsn.offset);
+ printf("\n");
+ free(argp);
+ return (0);
+}
+
+/*
+ * PUBLIC: int __db_ovref_read __P((void *, __db_ovref_args **));
+ */
+int
+__db_ovref_read(recbuf, argpp)
+ void *recbuf;
+ __db_ovref_args **argpp;
+{
+ __db_ovref_args *argp;
+ u_int8_t *bp;
+
+ argp = (__db_ovref_args *)malloc(sizeof(__db_ovref_args) +
+ sizeof(DB_TXN));
+ if (argp == NULL)
+ return (ENOMEM);
+ argp->txnid = (DB_TXN *)&argp[1];
+ bp = recbuf;
+ memcpy(&argp->type, bp, sizeof(argp->type));
+ bp += sizeof(argp->type);
+ memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid));
+ bp += sizeof(argp->txnid->txnid);
+ memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN));
+ bp += sizeof(DB_LSN);
+ memcpy(&argp->fileid, bp, sizeof(argp->fileid));
+ bp += sizeof(argp->fileid);
+ memcpy(&argp->pgno, bp, sizeof(argp->pgno));
+ bp += sizeof(argp->pgno);
+ memcpy(&argp->lsn, bp, sizeof(argp->lsn));
+ bp += sizeof(argp->lsn);
+ *argpp = argp;
+ return (0);
+}
+
+/*
+ * PUBLIC: int __db_relink_log
+ * PUBLIC: __P((DB_LOG *, DB_TXN *, DB_LSN *, u_int32_t,
+ * PUBLIC: u_int32_t, db_pgno_t, DB_LSN *, db_pgno_t,
+ * PUBLIC: DB_LSN *, db_pgno_t, DB_LSN *));
+ */
+int __db_relink_log(logp, txnid, ret_lsnp, flags,
+ fileid, pgno, lsn, prev, lsn_prev, next,
+ lsn_next)
+ DB_LOG *logp;
+ DB_TXN *txnid;
+ DB_LSN *ret_lsnp;
+ u_int32_t flags;
+ u_int32_t fileid;
+ db_pgno_t pgno;
+ DB_LSN * lsn;
+ db_pgno_t prev;
+ DB_LSN * lsn_prev;
+ db_pgno_t next;
+ DB_LSN * lsn_next;
+{
+ DBT logrec;
+ DB_LSN *lsnp, null_lsn;
+ u_int32_t rectype, txn_num;
+ int ret;
+ u_int8_t *bp;
+
+ rectype = DB_db_relink;
+ txn_num = txnid == NULL ? 0 : txnid->txnid;
+ if (txnid == NULL) {
+ null_lsn.file = 0;
+ null_lsn.offset = 0;
+ lsnp = &null_lsn;
+ } else
+ lsnp = &txnid->last_lsn;
+ logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN)
+ + sizeof(fileid)
+ + sizeof(pgno)
+ + sizeof(*lsn)
+ + sizeof(prev)
+ + sizeof(*lsn_prev)
+ + sizeof(next)
+ + sizeof(*lsn_next);
+ if ((logrec.data = (void *)malloc(logrec.size)) == NULL)
+ return (ENOMEM);
+
+ bp = logrec.data;
+ memcpy(bp, &rectype, sizeof(rectype));
+ bp += sizeof(rectype);
+ memcpy(bp, &txn_num, sizeof(txn_num));
+ bp += sizeof(txn_num);
+ memcpy(bp, lsnp, sizeof(DB_LSN));
+ bp += sizeof(DB_LSN);
+ memcpy(bp, &fileid, sizeof(fileid));
+ bp += sizeof(fileid);
+ memcpy(bp, &pgno, sizeof(pgno));
+ bp += sizeof(pgno);
+ if (lsn != NULL)
+ memcpy(bp, lsn, sizeof(*lsn));
+ else
+ memset(bp, 0, sizeof(*lsn));
+ bp += sizeof(*lsn);
+ memcpy(bp, &prev, sizeof(prev));
+ bp += sizeof(prev);
+ if (lsn_prev != NULL)
+ memcpy(bp, lsn_prev, sizeof(*lsn_prev));
+ else
+ memset(bp, 0, sizeof(*lsn_prev));
+ bp += sizeof(*lsn_prev);
+ memcpy(bp, &next, sizeof(next));
+ bp += sizeof(next);
+ if (lsn_next != NULL)
+ memcpy(bp, lsn_next, sizeof(*lsn_next));
+ else
+ memset(bp, 0, sizeof(*lsn_next));
+ bp += sizeof(*lsn_next);
+#ifdef DEBUG
+ if ((u_int32_t)(bp - (u_int8_t *)logrec.data) != logrec.size)
+ fprintf(stderr, "Error in log record length");
+#endif
+ ret = log_put(logp, ret_lsnp, (DBT *)&logrec, flags);
+ if (txnid != NULL)
+ txnid->last_lsn = *ret_lsnp;
+ free(logrec.data);
+ return (ret);
+}
+
+/*
+ * PUBLIC: int __db_relink_print
+ * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
+ */
+
+int
+__db_relink_print(notused1, dbtp, lsnp, notused3, notused4)
+ DB_LOG *notused1;
+ DBT *dbtp;
+ DB_LSN *lsnp;
+ int notused3;
+ void *notused4;
+{
+ __db_relink_args *argp;
+ u_int32_t i;
+ int c, ret;
+
+ i = 0;
+ c = 0;
+ notused1 = NULL;
+ notused3 = 0;
+ notused4 = NULL;
+
+ if((ret = __db_relink_read(dbtp->data, &argp)) != 0)
+ return (ret);
+ printf("[%lu][%lu]db_relink: rec: %lu txnid %lx prevlsn [%lu][%lu]\n",
+ (u_long)lsnp->file,
+ (u_long)lsnp->offset,
+ (u_long)argp->type,
+ (u_long)argp->txnid->txnid,
+ (u_long)argp->prev_lsn.file,
+ (u_long)argp->prev_lsn.offset);
+ printf("\tfileid: %lu\n", (u_long)argp->fileid);
+ printf("\tpgno: %lu\n", (u_long)argp->pgno);
+ printf("\tlsn: [%lu][%lu]\n",
+ (u_long)argp->lsn.file, (u_long)argp->lsn.offset);
+ printf("\tprev: %lu\n", (u_long)argp->prev);
+ printf("\tlsn_prev: [%lu][%lu]\n",
+ (u_long)argp->lsn_prev.file, (u_long)argp->lsn_prev.offset);
+ printf("\tnext: %lu\n", (u_long)argp->next);
+ printf("\tlsn_next: [%lu][%lu]\n",
+ (u_long)argp->lsn_next.file, (u_long)argp->lsn_next.offset);
+ printf("\n");
+ free(argp);
+ return (0);
+}
+
+/*
+ * PUBLIC: int __db_relink_read __P((void *, __db_relink_args **));
+ */
+int
+__db_relink_read(recbuf, argpp)
+ void *recbuf;
+ __db_relink_args **argpp;
+{
+ __db_relink_args *argp;
+ u_int8_t *bp;
+
+ argp = (__db_relink_args *)malloc(sizeof(__db_relink_args) +
+ sizeof(DB_TXN));
+ if (argp == NULL)
+ return (ENOMEM);
+ argp->txnid = (DB_TXN *)&argp[1];
+ bp = recbuf;
+ memcpy(&argp->type, bp, sizeof(argp->type));
+ bp += sizeof(argp->type);
+ memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid));
+ bp += sizeof(argp->txnid->txnid);
+ memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN));
+ bp += sizeof(DB_LSN);
+ memcpy(&argp->fileid, bp, sizeof(argp->fileid));
+ bp += sizeof(argp->fileid);
+ memcpy(&argp->pgno, bp, sizeof(argp->pgno));
+ bp += sizeof(argp->pgno);
+ memcpy(&argp->lsn, bp, sizeof(argp->lsn));
+ bp += sizeof(argp->lsn);
+ memcpy(&argp->prev, bp, sizeof(argp->prev));
+ bp += sizeof(argp->prev);
+ memcpy(&argp->lsn_prev, bp, sizeof(argp->lsn_prev));
+ bp += sizeof(argp->lsn_prev);
+ memcpy(&argp->next, bp, sizeof(argp->next));
+ bp += sizeof(argp->next);
+ memcpy(&argp->lsn_next, bp, sizeof(argp->lsn_next));
+ bp += sizeof(argp->lsn_next);
+ *argpp = argp;
+ return (0);
+}
+
+/*
+ * PUBLIC: int __db_addpage_log
+ * PUBLIC: __P((DB_LOG *, DB_TXN *, DB_LSN *, u_int32_t,
+ * PUBLIC: u_int32_t, db_pgno_t, DB_LSN *, db_pgno_t,
+ * PUBLIC: DB_LSN *));
+ */
+int __db_addpage_log(logp, txnid, ret_lsnp, flags,
+ fileid, pgno, lsn, nextpgno, nextlsn)
+ DB_LOG *logp;
+ DB_TXN *txnid;
+ DB_LSN *ret_lsnp;
+ u_int32_t flags;
+ u_int32_t fileid;
+ db_pgno_t pgno;
+ DB_LSN * lsn;
+ db_pgno_t nextpgno;
+ DB_LSN * nextlsn;
+{
+ DBT logrec;
+ DB_LSN *lsnp, null_lsn;
+ u_int32_t rectype, txn_num;
+ int ret;
+ u_int8_t *bp;
+
+ rectype = DB_db_addpage;
+ txn_num = txnid == NULL ? 0 : txnid->txnid;
+ if (txnid == NULL) {
+ null_lsn.file = 0;
+ null_lsn.offset = 0;
+ lsnp = &null_lsn;
+ } else
+ lsnp = &txnid->last_lsn;
+ logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN)
+ + sizeof(fileid)
+ + sizeof(pgno)
+ + sizeof(*lsn)
+ + sizeof(nextpgno)
+ + sizeof(*nextlsn);
+ if ((logrec.data = (void *)malloc(logrec.size)) == NULL)
+ return (ENOMEM);
+
+ bp = logrec.data;
+ memcpy(bp, &rectype, sizeof(rectype));
+ bp += sizeof(rectype);
+ memcpy(bp, &txn_num, sizeof(txn_num));
+ bp += sizeof(txn_num);
+ memcpy(bp, lsnp, sizeof(DB_LSN));
+ bp += sizeof(DB_LSN);
+ memcpy(bp, &fileid, sizeof(fileid));
+ bp += sizeof(fileid);
+ memcpy(bp, &pgno, sizeof(pgno));
+ bp += sizeof(pgno);
+ if (lsn != NULL)
+ memcpy(bp, lsn, sizeof(*lsn));
+ else
+ memset(bp, 0, sizeof(*lsn));
+ bp += sizeof(*lsn);
+ memcpy(bp, &nextpgno, sizeof(nextpgno));
+ bp += sizeof(nextpgno);
+ if (nextlsn != NULL)
+ memcpy(bp, nextlsn, sizeof(*nextlsn));
+ else
+ memset(bp, 0, sizeof(*nextlsn));
+ bp += sizeof(*nextlsn);
+#ifdef DEBUG
+ if ((u_int32_t)(bp - (u_int8_t *)logrec.data) != logrec.size)
+ fprintf(stderr, "Error in log record length");
+#endif
+ ret = log_put(logp, ret_lsnp, (DBT *)&logrec, flags);
+ if (txnid != NULL)
+ txnid->last_lsn = *ret_lsnp;
+ free(logrec.data);
+ return (ret);
+}
+
+/*
+ * PUBLIC: int __db_addpage_print
+ * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
+ */
+
+int
+__db_addpage_print(notused1, dbtp, lsnp, notused3, notused4)
+ DB_LOG *notused1;
+ DBT *dbtp;
+ DB_LSN *lsnp;
+ int notused3;
+ void *notused4;
+{
+ __db_addpage_args *argp;
+ u_int32_t i;
+ int c, ret;
+
+ i = 0;
+ c = 0;
+ notused1 = NULL;
+ notused3 = 0;
+ notused4 = NULL;
+
+ if((ret = __db_addpage_read(dbtp->data, &argp)) != 0)
+ return (ret);
+ printf("[%lu][%lu]db_addpage: rec: %lu txnid %lx prevlsn [%lu][%lu]\n",
+ (u_long)lsnp->file,
+ (u_long)lsnp->offset,
+ (u_long)argp->type,
+ (u_long)argp->txnid->txnid,
+ (u_long)argp->prev_lsn.file,
+ (u_long)argp->prev_lsn.offset);
+ printf("\tfileid: %lu\n", (u_long)argp->fileid);
+ printf("\tpgno: %lu\n", (u_long)argp->pgno);
+ printf("\tlsn: [%lu][%lu]\n",
+ (u_long)argp->lsn.file, (u_long)argp->lsn.offset);
+ printf("\tnextpgno: %lu\n", (u_long)argp->nextpgno);
+ printf("\tnextlsn: [%lu][%lu]\n",
+ (u_long)argp->nextlsn.file, (u_long)argp->nextlsn.offset);
+ printf("\n");
+ free(argp);
+ return (0);
+}
+
+/*
+ * PUBLIC: int __db_addpage_read __P((void *, __db_addpage_args **));
+ */
+int
+__db_addpage_read(recbuf, argpp)
+ void *recbuf;
+ __db_addpage_args **argpp;
+{
+ __db_addpage_args *argp;
+ u_int8_t *bp;
+
+ argp = (__db_addpage_args *)malloc(sizeof(__db_addpage_args) +
+ sizeof(DB_TXN));
+ if (argp == NULL)
+ return (ENOMEM);
+ argp->txnid = (DB_TXN *)&argp[1];
+ bp = recbuf;
+ memcpy(&argp->type, bp, sizeof(argp->type));
+ bp += sizeof(argp->type);
+ memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid));
+ bp += sizeof(argp->txnid->txnid);
+ memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN));
+ bp += sizeof(DB_LSN);
+ memcpy(&argp->fileid, bp, sizeof(argp->fileid));
+ bp += sizeof(argp->fileid);
+ memcpy(&argp->pgno, bp, sizeof(argp->pgno));
+ bp += sizeof(argp->pgno);
+ memcpy(&argp->lsn, bp, sizeof(argp->lsn));
+ bp += sizeof(argp->lsn);
+ memcpy(&argp->nextpgno, bp, sizeof(argp->nextpgno));
+ bp += sizeof(argp->nextpgno);
+ memcpy(&argp->nextlsn, bp, sizeof(argp->nextlsn));
+ bp += sizeof(argp->nextlsn);
+ *argpp = argp;
+ return (0);
+}
+
+/*
+ * PUBLIC: int __db_debug_log
+ * PUBLIC: __P((DB_LOG *, DB_TXN *, DB_LSN *, u_int32_t,
+ * PUBLIC: DBT *, u_int32_t, DBT *, DBT *,
+ * PUBLIC: u_int32_t));
+ */
+int __db_debug_log(logp, txnid, ret_lsnp, flags,
+ op, fileid, key, data, arg_flags)
+ DB_LOG *logp;
+ DB_TXN *txnid;
+ DB_LSN *ret_lsnp;
+ u_int32_t flags;
+ DBT *op;
+ u_int32_t fileid;
+ DBT *key;
+ DBT *data;
+ u_int32_t arg_flags;
+{
+ DBT logrec;
+ DB_LSN *lsnp, null_lsn;
+ u_int32_t zero;
+ u_int32_t rectype, txn_num;
+ int ret;
+ u_int8_t *bp;
+
+ rectype = DB_db_debug;
+ txn_num = txnid == NULL ? 0 : txnid->txnid;
+ if (txnid == NULL) {
+ null_lsn.file = 0;
+ null_lsn.offset = 0;
+ lsnp = &null_lsn;
+ } else
+ lsnp = &txnid->last_lsn;
+ logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN)
+ + sizeof(u_int32_t) + (op == NULL ? 0 : op->size)
+ + sizeof(fileid)
+ + sizeof(u_int32_t) + (key == NULL ? 0 : key->size)
+ + sizeof(u_int32_t) + (data == NULL ? 0 : data->size)
+ + sizeof(arg_flags);
+ if ((logrec.data = (void *)malloc(logrec.size)) == NULL)
+ return (ENOMEM);
+
+ bp = logrec.data;
+ memcpy(bp, &rectype, sizeof(rectype));
+ bp += sizeof(rectype);
+ memcpy(bp, &txn_num, sizeof(txn_num));
+ bp += sizeof(txn_num);
+ memcpy(bp, lsnp, sizeof(DB_LSN));
+ bp += sizeof(DB_LSN);
+ if (op == NULL) {
+ zero = 0;
+ memcpy(bp, &zero, sizeof(u_int32_t));
+ bp += sizeof(u_int32_t);
+ } else {
+ memcpy(bp, &op->size, sizeof(op->size));
+ bp += sizeof(op->size);
+ memcpy(bp, op->data, op->size);
+ bp += op->size;
+ }
+ memcpy(bp, &fileid, sizeof(fileid));
+ bp += sizeof(fileid);
+ if (key == NULL) {
+ zero = 0;
+ memcpy(bp, &zero, sizeof(u_int32_t));
+ bp += sizeof(u_int32_t);
+ } else {
+ memcpy(bp, &key->size, sizeof(key->size));
+ bp += sizeof(key->size);
+ memcpy(bp, key->data, key->size);
+ bp += key->size;
+ }
+ if (data == NULL) {
+ zero = 0;
+ memcpy(bp, &zero, sizeof(u_int32_t));
+ bp += sizeof(u_int32_t);
+ } else {
+ memcpy(bp, &data->size, sizeof(data->size));
+ bp += sizeof(data->size);
+ memcpy(bp, data->data, data->size);
+ bp += data->size;
+ }
+ memcpy(bp, &arg_flags, sizeof(arg_flags));
+ bp += sizeof(arg_flags);
+#ifdef DEBUG
+ if ((u_int32_t)(bp - (u_int8_t *)logrec.data) != logrec.size)
+ fprintf(stderr, "Error in log record length");
+#endif
+ ret = log_put(logp, ret_lsnp, (DBT *)&logrec, flags);
+ if (txnid != NULL)
+ txnid->last_lsn = *ret_lsnp;
+ free(logrec.data);
+ return (ret);
+}
+
+/*
+ * PUBLIC: int __db_debug_print
+ * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
+ */
+
+int
+__db_debug_print(notused1, dbtp, lsnp, notused3, notused4)
+ DB_LOG *notused1;
+ DBT *dbtp;
+ DB_LSN *lsnp;
+ int notused3;
+ void *notused4;
+{
+ __db_debug_args *argp;
+ u_int32_t i;
+ int c, ret;
+
+ i = 0;
+ c = 0;
+ notused1 = NULL;
+ notused3 = 0;
+ notused4 = NULL;
+
+ if((ret = __db_debug_read(dbtp->data, &argp)) != 0)
+ return (ret);
+ printf("[%lu][%lu]db_debug: rec: %lu txnid %lx prevlsn [%lu][%lu]\n",
+ (u_long)lsnp->file,
+ (u_long)lsnp->offset,
+ (u_long)argp->type,
+ (u_long)argp->txnid->txnid,
+ (u_long)argp->prev_lsn.file,
+ (u_long)argp->prev_lsn.offset);
+ printf("\top: ");
+ for (i = 0; i < argp->op.size; i++) {
+ c = ((char *)argp->op.data)[i];
+ if (isprint(c) || c == 0xa)
+ putchar(c);
+ else
+ printf("%#x ", c);
+ }
+ printf("\n");
+ printf("\tfileid: %lu\n", (u_long)argp->fileid);
+ printf("\tkey: ");
+ for (i = 0; i < argp->key.size; i++) {
+ c = ((char *)argp->key.data)[i];
+ if (isprint(c) || c == 0xa)
+ putchar(c);
+ else
+ printf("%#x ", c);
+ }
+ printf("\n");
+ printf("\tdata: ");
+ for (i = 0; i < argp->data.size; i++) {
+ c = ((char *)argp->data.data)[i];
+ if (isprint(c) || c == 0xa)
+ putchar(c);
+ else
+ printf("%#x ", c);
+ }
+ printf("\n");
+ printf("\targ_flags: %lu\n", (u_long)argp->arg_flags);
+ printf("\n");
+ free(argp);
+ return (0);
+}
+
+/*
+ * PUBLIC: int __db_debug_read __P((void *, __db_debug_args **));
+ */
+int
+__db_debug_read(recbuf, argpp)
+ void *recbuf;
+ __db_debug_args **argpp;
+{
+ __db_debug_args *argp;
+ u_int8_t *bp;
+
+ argp = (__db_debug_args *)malloc(sizeof(__db_debug_args) +
+ sizeof(DB_TXN));
+ if (argp == NULL)
+ return (ENOMEM);
+ argp->txnid = (DB_TXN *)&argp[1];
+ bp = recbuf;
+ memcpy(&argp->type, bp, sizeof(argp->type));
+ bp += sizeof(argp->type);
+ memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid));
+ bp += sizeof(argp->txnid->txnid);
+ memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN));
+ bp += sizeof(DB_LSN);
+ memcpy(&argp->op.size, bp, sizeof(u_int32_t));
+ bp += sizeof(u_int32_t);
+ argp->op.data = bp;
+ bp += argp->op.size;
+ memcpy(&argp->fileid, bp, sizeof(argp->fileid));
+ bp += sizeof(argp->fileid);
+ memcpy(&argp->key.size, bp, sizeof(u_int32_t));
+ bp += sizeof(u_int32_t);
+ argp->key.data = bp;
+ bp += argp->key.size;
+ memcpy(&argp->data.size, bp, sizeof(u_int32_t));
+ bp += sizeof(u_int32_t);
+ argp->data.data = bp;
+ bp += argp->data.size;
+ memcpy(&argp->arg_flags, bp, sizeof(argp->arg_flags));
+ bp += sizeof(argp->arg_flags);
+ *argpp = argp;
+ return (0);
+}
+
+/*
+ * PUBLIC: int __db_noop_log
+ * PUBLIC: __P((DB_LOG *, DB_TXN *, DB_LSN *, u_int32_t));
+ */
+int __db_noop_log(logp, txnid, ret_lsnp, flags)
+ DB_LOG *logp;
+ DB_TXN *txnid;
+ DB_LSN *ret_lsnp;
+ u_int32_t flags;
+{
+ DBT logrec;
+ DB_LSN *lsnp, null_lsn;
+ u_int32_t rectype, txn_num;
+ int ret;
+ u_int8_t *bp;
+
+ rectype = DB_db_noop;
+ txn_num = txnid == NULL ? 0 : txnid->txnid;
+ if (txnid == NULL) {
+ null_lsn.file = 0;
+ null_lsn.offset = 0;
+ lsnp = &null_lsn;
+ } else
+ lsnp = &txnid->last_lsn;
+ logrec.size = sizeof(rectype) + sizeof(txn_num) + sizeof(DB_LSN);
+ if ((logrec.data = (void *)malloc(logrec.size)) == NULL)
+ return (ENOMEM);
+
+ bp = logrec.data;
+ memcpy(bp, &rectype, sizeof(rectype));
+ bp += sizeof(rectype);
+ memcpy(bp, &txn_num, sizeof(txn_num));
+ bp += sizeof(txn_num);
+ memcpy(bp, lsnp, sizeof(DB_LSN));
+ bp += sizeof(DB_LSN);
+#ifdef DEBUG
+ if ((u_int32_t)(bp - (u_int8_t *)logrec.data) != logrec.size)
+ fprintf(stderr, "Error in log record length");
+#endif
+ ret = log_put(logp, ret_lsnp, (DBT *)&logrec, flags);
+ if (txnid != NULL)
+ txnid->last_lsn = *ret_lsnp;
+ free(logrec.data);
+ return (ret);
+}
+
+/*
+ * PUBLIC: int __db_noop_print
+ * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
+ */
+
+int
+__db_noop_print(notused1, dbtp, lsnp, notused3, notused4)
+ DB_LOG *notused1;
+ DBT *dbtp;
+ DB_LSN *lsnp;
+ int notused3;
+ void *notused4;
+{
+ __db_noop_args *argp;
+ u_int32_t i;
+ int c, ret;
+
+ i = 0;
+ c = 0;
+ notused1 = NULL;
+ notused3 = 0;
+ notused4 = NULL;
+
+ if((ret = __db_noop_read(dbtp->data, &argp)) != 0)
+ return (ret);
+ printf("[%lu][%lu]db_noop: rec: %lu txnid %lx prevlsn [%lu][%lu]\n",
+ (u_long)lsnp->file,
+ (u_long)lsnp->offset,
+ (u_long)argp->type,
+ (u_long)argp->txnid->txnid,
+ (u_long)argp->prev_lsn.file,
+ (u_long)argp->prev_lsn.offset);
+ printf("\n");
+ free(argp);
+ return (0);
+}
+
+/*
+ * PUBLIC: int __db_noop_read __P((void *, __db_noop_args **));
+ */
+int
+__db_noop_read(recbuf, argpp)
+ void *recbuf;
+ __db_noop_args **argpp;
+{
+ __db_noop_args *argp;
+ u_int8_t *bp;
+
+ argp = (__db_noop_args *)malloc(sizeof(__db_noop_args) +
+ sizeof(DB_TXN));
+ if (argp == NULL)
+ return (ENOMEM);
+ argp->txnid = (DB_TXN *)&argp[1];
+ bp = recbuf;
+ memcpy(&argp->type, bp, sizeof(argp->type));
+ bp += sizeof(argp->type);
+ memcpy(&argp->txnid->txnid, bp, sizeof(argp->txnid->txnid));
+ bp += sizeof(argp->txnid->txnid);
+ memcpy(&argp->prev_lsn, bp, sizeof(DB_LSN));
+ bp += sizeof(DB_LSN);
+ *argpp = argp;
+ return (0);
+}
+
+/*
+ * PUBLIC: int __db_init_print __P((DB_ENV *));
+ */
+int
+__db_init_print(dbenv)
+ DB_ENV *dbenv;
+{
+ int ret;
+
+ if ((ret = __db_add_recovery(dbenv,
+ __db_addrem_print, DB_db_addrem)) != 0)
+ return (ret);
+ if ((ret = __db_add_recovery(dbenv,
+ __db_split_print, DB_db_split)) != 0)
+ return (ret);
+ if ((ret = __db_add_recovery(dbenv,
+ __db_big_print, DB_db_big)) != 0)
+ return (ret);
+ if ((ret = __db_add_recovery(dbenv,
+ __db_ovref_print, DB_db_ovref)) != 0)
+ return (ret);
+ if ((ret = __db_add_recovery(dbenv,
+ __db_relink_print, DB_db_relink)) != 0)
+ return (ret);
+ if ((ret = __db_add_recovery(dbenv,
+ __db_addpage_print, DB_db_addpage)) != 0)
+ return (ret);
+ if ((ret = __db_add_recovery(dbenv,
+ __db_debug_print, DB_db_debug)) != 0)
+ return (ret);
+ if ((ret = __db_add_recovery(dbenv,
+ __db_noop_print, DB_db_noop)) != 0)
+ return (ret);
+ return (0);
+}
+
+/*
+ * PUBLIC: int __db_init_recover __P((DB_ENV *));
+ */
+int
+__db_init_recover(dbenv)
+ DB_ENV *dbenv;
+{
+ int ret;
+
+ if ((ret = __db_add_recovery(dbenv,
+ __db_addrem_recover, DB_db_addrem)) != 0)
+ return (ret);
+ if ((ret = __db_add_recovery(dbenv,
+ __db_split_recover, DB_db_split)) != 0)
+ return (ret);
+ if ((ret = __db_add_recovery(dbenv,
+ __db_big_recover, DB_db_big)) != 0)
+ return (ret);
+ if ((ret = __db_add_recovery(dbenv,
+ __db_ovref_recover, DB_db_ovref)) != 0)
+ return (ret);
+ if ((ret = __db_add_recovery(dbenv,
+ __db_relink_recover, DB_db_relink)) != 0)
+ return (ret);
+ if ((ret = __db_add_recovery(dbenv,
+ __db_addpage_recover, DB_db_addpage)) != 0)
+ return (ret);
+ if ((ret = __db_add_recovery(dbenv,
+ __db_debug_recover, DB_db_debug)) != 0)
+ return (ret);
+ if ((ret = __db_add_recovery(dbenv,
+ __db_noop_recover, DB_db_noop)) != 0)
+ return (ret);
+ return (0);
+}
+
diff --git a/db2/db/db_conv.c b/db2/db/db_conv.c
new file mode 100644
index 0000000000..39527c6804
--- /dev/null
+++ b/db2/db/db_conv.c
@@ -0,0 +1,219 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1996, 1997
+ * Sleepycat Software. All rights reserved.
+ */
+/*
+ * Copyright (c) 1990, 1993, 1994, 1995, 1996
+ * Keith Bostic. All rights reserved.
+ */
+/*
+ * Copyright (c) 1990, 1993, 1994, 1995
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#ifndef lint
+static const char sccsid[] = "@(#)db_conv.c 10.4 (Sleepycat) 8/15/97";
+#endif /* not lint */
+
+#ifndef NO_SYSTEM_INCLUDES
+#include <sys/types.h>
+
+#include <errno.h>
+#endif
+
+#include "db_int.h"
+#include "db_page.h"
+#include "db_swap.h"
+#include "db_am.h"
+
+static int __db_convert __P((db_pgno_t, void *, int));
+
+/*
+ * __db_pgin, __db_pgout --
+ *
+ * PUBLIC: int __db_pgin __P((db_pgno_t, void *));
+ * PUBLIC: int __db_pgout __P((db_pgno_t, void *));
+ */
+int
+__db_pgin(pg, pp)
+ db_pgno_t pg;
+ void *pp;
+{
+ return (__db_convert(pg, pp, 1));
+}
+
+int
+__db_pgout(pg, pp)
+ db_pgno_t pg;
+ void *pp;
+{
+ return (__db_convert(pg, pp, 0));
+}
+
+/*
+ * __db_convert --
+ * Actually convert a page.
+ */
+static int
+__db_convert(pg, pp, pgin)
+ db_pgno_t pg; /* Unused, but left for the future. */
+ void *pp;
+ int pgin;
+{
+ BINTERNAL *bi;
+ BKEYDATA *bk;
+ BOVERFLOW *bo;
+ HKEYDATA *hk;
+ PAGE *h;
+ RINTERNAL *ri;
+ db_indx_t i;
+ u_int8_t *p;
+
+ h = pp;
+ if (pgin) {
+ M_32_SWAP(h->lsn.file);
+ M_32_SWAP(h->lsn.offset);
+ M_32_SWAP(h->pgno);
+ M_32_SWAP(h->prev_pgno);
+ M_32_SWAP(h->next_pgno);
+ M_16_SWAP(h->entries);
+ M_16_SWAP(h->hf_offset);
+ }
+
+ switch (h->type) {
+ case P_HASH:
+ for (i = 0; i < NUM_ENT(h); i++) {
+ if (pgin)
+ M_16_SWAP(h->inp[i]);
+
+ hk = GET_HKEYDATA(h, i);
+ switch (hk->type) {
+ case H_KEYDATA:
+ break;
+ case H_DUPLICATE:
+ case H_OFFPAGE:
+ p = (u_int8_t *)hk + sizeof(u_int8_t);
+ ++p;
+ SWAP32(p); /* tlen */
+ SWAP32(p); /* pgno */
+ SWAP16(p); /* offset */
+ SWAP16(p); /* len */
+ break;
+ }
+
+ if (!pgin)
+ M_16_SWAP(h->inp[i]);
+ }
+ break;
+ case P_LBTREE:
+ case P_LRECNO:
+ case P_DUPLICATE:
+ for (i = 0; i < NUM_ENT(h); i++) {
+ if (pgin)
+ M_16_SWAP(h->inp[i]);
+
+ bk = GET_BKEYDATA(h, i);
+ switch (bk->type) {
+ case B_KEYDATA:
+ M_16_SWAP(bk->len);
+ break;
+ case B_DUPLICATE:
+ case B_OVERFLOW:
+ bo = (BOVERFLOW *)bk;
+ M_32_SWAP(bo->tlen);
+ M_32_SWAP(bo->pgno);
+ break;
+ }
+
+ if (!pgin)
+ M_16_SWAP(h->inp[i]);
+ }
+ break;
+ case P_IBTREE:
+ for (i = 0; i < NUM_ENT(h); i++) {
+ if (pgin)
+ M_16_SWAP(h->inp[i]);
+
+ bi = GET_BINTERNAL(h, i);
+ switch (bi->type) {
+ case B_KEYDATA:
+ M_16_SWAP(bi->len);
+ M_32_SWAP(bi->pgno);
+ M_32_SWAP(bi->nrecs);
+ break;
+ case B_DUPLICATE:
+ case B_OVERFLOW:
+ bo = (BOVERFLOW *)bi;
+ M_32_SWAP(bo->tlen);
+ M_32_SWAP(bo->pgno);
+ break;
+ }
+
+ if (!pgin)
+ M_16_SWAP(h->inp[i]);
+ }
+ break;
+ case P_IRECNO:
+ for (i = 0; i < NUM_ENT(h); i++) {
+ if (pgin)
+ M_16_SWAP(h->inp[i]);
+
+ ri = GET_RINTERNAL(h, i);
+ M_32_SWAP(ri->pgno);
+ M_32_SWAP(ri->nrecs);
+
+ if (!pgin)
+ M_16_SWAP(h->inp[i]);
+ }
+ case P_OVERFLOW:
+ case P_INVALID:
+ /* Nothing to do. */
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ if (!pgin) {
+ /* Swap the header information. */
+ M_32_SWAP(h->lsn.file);
+ M_32_SWAP(h->lsn.offset);
+ M_32_SWAP(h->pgno);
+ M_32_SWAP(h->prev_pgno);
+ M_32_SWAP(h->next_pgno);
+ M_16_SWAP(h->entries);
+ M_16_SWAP(h->hf_offset);
+ }
+ return (0);
+}
diff --git a/db2/db/db_dispatch.c b/db2/db/db_dispatch.c
new file mode 100644
index 0000000000..3d7b162d75
--- /dev/null
+++ b/db2/db/db_dispatch.c
@@ -0,0 +1,270 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1996, 1997
+ * 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 Berkeley by
+ * Margo Seltzer.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#ifndef lint
+static const char sccsid[] = "@(#)db_dispatch.c 10.5 (Sleepycat) 7/2/97";
+#endif /* not lint */
+
+#ifndef NO_SYSTEM_INCLUDES
+#include <sys/types.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#endif
+
+#include "db_int.h"
+#include "db_page.h"
+#include "db_dispatch.h"
+#include "db_am.h"
+#include "common_ext.h"
+
+/*
+ * Data structures to manage the DB dispatch table. The dispatch table
+ * is a dynamically allocated array of pointers to dispatch functions.
+ * The dispatch_size is the number of entries possible in the current
+ * dispatch table and the dispatch_valid is the number of valid entries
+ * in the dispatch table.
+ */
+static int (**dispatch_table) __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
+static u_int32_t dispatch_size = 0;
+
+/*
+ * __db_dispatch --
+ *
+ * This is the transaction dispatch function used by the db access methods.
+ * It is designed to handle the record format used by all the access
+ * methods (the one automatically generated by the db_{h,log,read}.sh
+ * scripts in the tools directory). An application using a different
+ * recovery paradigm will supply a different dispatch function to txn_open.
+ *
+ * PUBLIC: int __db_dispatch __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
+ */
+int
+__db_dispatch(logp, db, lsnp, redo, info)
+ DB_LOG *logp; /* The log file. */
+ DBT *db; /* The log record upon which to dispatch. */
+ DB_LSN *lsnp; /* The lsn of the record being dispatched. */
+ int redo; /* Redo this op (or undo it). */
+ void *info;
+{
+ u_int32_t rectype, txnid;
+
+ memcpy(&rectype, db->data, sizeof(rectype));
+ memcpy(&txnid, (u_int8_t *)db->data + sizeof(rectype), sizeof(txnid));
+
+ switch (redo) {
+ case TXN_REDO:
+ case TXN_UNDO:
+ return ((dispatch_table[rectype])(logp, db, lsnp, redo, info));
+ case TXN_OPENFILES:
+ if (rectype < DB_txn_BEGIN )
+ return ((dispatch_table[rectype])(logp,
+ db, lsnp, redo, info));
+ break;
+ case TXN_BACKWARD_ROLL:
+ /*
+ * Running full recovery in the backward pass. If we've
+ * seen this txnid before and added to it our commit list,
+ * then we do nothing during this pass. If we've never
+ * seen it, then we call the appropriate recovery routine
+ * in "abort mode".
+ */
+ if (__db_txnlist_find(info, txnid) == DB_NOTFOUND)
+ return ((dispatch_table[rectype])(logp,
+ db, lsnp, TXN_UNDO, info));
+ break;
+ case TXN_FORWARD_ROLL:
+ /*
+ * In the forward pass, if we haven't seen the transaction,
+ * do nothing, else recovery it.
+ */
+ if (__db_txnlist_find(info, txnid) != DB_NOTFOUND)
+ return ((dispatch_table[rectype])(logp,
+ db, lsnp, TXN_REDO, info));
+ break;
+ default:
+ abort();
+ }
+ return (0);
+}
+
+/*
+ * __db_add_recovery --
+ *
+ * PUBLIC: int __db_add_recovery __P((DB_ENV *,
+ * PUBLIC: int (*)(DB_LOG *, DBT *, DB_LSN *, int, void *), u_int32_t));
+ */
+int
+__db_add_recovery(dbenv, func, ndx)
+ DB_ENV *dbenv;
+ int (*func) __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
+ u_int32_t ndx;
+{
+ u_int32_t i;
+
+ /* Check if function is already registered. */
+ if (dispatch_table && ndx < dispatch_size &&
+ dispatch_table[ndx] != 0 && dispatch_table[ndx] != func)
+ return (DB_REGISTERED);
+
+ /* Check if we have to grow the table. */
+ if (ndx >= dispatch_size) {
+ if (dispatch_table == NULL)
+ dispatch_table = (int (**)
+ __P((DB_LOG *, DBT *, DB_LSN *, int, void *)))
+ malloc(DB_user_BEGIN * sizeof(dispatch_table[0]));
+ else
+ dispatch_table = (int (**)
+ __P((DB_LOG *, DBT *, DB_LSN *, int, void *)))
+ realloc(dispatch_table, (DB_user_BEGIN +
+ dispatch_size) * sizeof(dispatch_table[0]));
+ if (dispatch_table == NULL) {
+ __db_err(dbenv, "%s", strerror(ENOMEM));
+ return (ENOMEM);
+ }
+ for (i = dispatch_size,
+ dispatch_size += DB_user_BEGIN; i < dispatch_size; ++i)
+ dispatch_table[i] = NULL;
+ }
+
+ dispatch_table[ndx] = func;
+ return (0);
+}
+
+/*
+ * __db_txnlist_init --
+ * Initialize transaction linked list.
+ *
+ * PUBLIC: int __db_txnlist_init __P((void *));
+ */
+int
+__db_txnlist_init(retp)
+ void *retp;
+{
+ __db_txnhead *headp;
+
+ if ((headp =
+ (struct __db_txnhead *)malloc(sizeof(struct __db_txnhead))) == NULL)
+ return (ENOMEM);
+
+ LIST_INIT(&headp->head);
+ headp->maxid = 0;
+
+ *(void **)retp = headp;
+ return (0);
+}
+
+/*
+ * __db_txnlist_add --
+ * Add an element to our transaction linked list.
+ *
+ * PUBLIC: int __db_txnlist_add __P((void *, u_int32_t));
+ */
+int
+__db_txnlist_add(listp, txnid)
+ void *listp;
+ u_int32_t txnid;
+{
+ __db_txnhead *hp;
+ __db_txnlist *elp;
+
+ if ((elp = (__db_txnlist *)malloc(sizeof(__db_txnlist))) == NULL)
+ return (ENOMEM);
+
+ elp->txnid = txnid;
+ hp = (struct __db_txnhead *)listp;
+ LIST_INSERT_HEAD(&hp->head, elp, links);
+ if (txnid > hp->maxid)
+ hp->maxid = txnid;
+
+ return (0);
+}
+
+/*
+ * __db_txnlist_find --
+ * Checks to see if txnid is in the txnid list, returns 1 if found,
+ * 0 if not found.
+ *
+ * PUBLIC: int __db_txnlist_find __P((void *, u_int32_t));
+ */
+int
+__db_txnlist_find(listp, txnid)
+ void *listp;
+ u_int32_t txnid;
+{
+ __db_txnlist *p;
+ __db_txnhead *hp;
+
+ if ((hp = (struct __db_txnhead *)listp) == NULL)
+ return (DB_NOTFOUND);
+
+ if (hp->maxid < txnid) {
+ hp->maxid = txnid;
+ return (DB_NOTFOUND);
+ }
+
+ for (p = hp->head.lh_first; p != NULL; p = p->links.le_next)
+ if (p->txnid == txnid)
+ return (0);
+
+ return (DB_NOTFOUND);
+}
+
+#ifdef DEBUG
+void
+__db_txnlist_print(listp)
+ void *listp;
+{
+ __db_txnlist *p;
+ __db_txnhead *hp;
+
+ hp = (struct __db_txnhead *)listp;
+ printf("Maxid: %lu\n", (u_long)hp->maxid);
+ for (p = hp->head.lh_first; p != NULL; p = p->links.le_next)
+ printf("TXNID: %lu\n", (u_long)p->txnid);
+}
+#endif
diff --git a/db2/db/db_dup.c b/db2/db/db_dup.c
new file mode 100644
index 0000000000..8d364d518e
--- /dev/null
+++ b/db2/db/db_dup.c
@@ -0,0 +1,680 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1996, 1997
+ * Sleepycat Software. All rights reserved.
+ */
+
+#include "config.h"
+
+#ifndef lint
+static const char sccsid[] = "@(#)db_dup.c 10.8 (Sleepycat) 7/20/97";
+#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"
+#include "db_page.h"
+#include "db_swap.h"
+#include "btree.h"
+#include "db_am.h"
+#include "common_ext.h"
+
+static int __db_addpage __P((DB *,
+ PAGE **, db_indx_t *, int (*)(DB *, u_int32_t, PAGE **)));
+static int __db_dsplit __P((DB *,
+ PAGE **, db_indx_t *, u_int32_t, int (*)(DB *, u_int32_t, PAGE **)));
+
+/*
+ * __db_dput --
+ * Put a duplicate item onto a duplicate page at the given index.
+ *
+ * PUBLIC: int __db_dput __P((DB *,
+ * PUBLIC: DBT *, PAGE **, db_indx_t *, int (*)(DB *, u_int32_t, PAGE **)));
+ */
+int
+__db_dput(dbp, dbt, pp, indxp, newfunc)
+ DB *dbp;
+ DBT *dbt;
+ PAGE **pp;
+ db_indx_t *indxp;
+ int (*newfunc) __P((DB *, u_int32_t, PAGE **));
+{
+ BOVERFLOW bo;
+ DBT *data_dbtp, hdr_dbt, *hdr_dbtp;
+ PAGE *pagep;
+ db_indx_t size, isize;
+ db_pgno_t pgno;
+ int ret;
+
+ /*
+ * We need some access method independent threshold for when we put
+ * a duplicate item onto an overflow page.
+ */
+ if (dbt->size > 0.25 * dbp->pgsize) {
+ if ((ret = __db_poff(dbp, dbt, &pgno, newfunc)) != 0)
+ return (ret);
+ bo.deleted = 0;
+ bo.type = B_OVERFLOW;
+ bo.tlen = dbt->size;
+ bo.pgno = pgno;
+ hdr_dbt.data = &bo;
+ hdr_dbt.size = isize = BOVERFLOW_SIZE;
+ hdr_dbtp = &hdr_dbt;
+ size = BOVERFLOW_PSIZE;
+ data_dbtp = NULL;
+ } else {
+ size = BKEYDATA_PSIZE(dbt->size);
+ isize = BKEYDATA_SIZE(dbt->size);
+ hdr_dbtp = NULL;
+ data_dbtp = dbt;
+ }
+
+ pagep = *pp;
+ if (size > P_FREESPACE(pagep)) {
+ if (*indxp == NUM_ENT(*pp) && NEXT_PGNO(*pp) == PGNO_INVALID)
+ ret = __db_addpage(dbp, pp, indxp, newfunc);
+ else
+ ret = __db_dsplit(dbp, pp, indxp, isize, newfunc);
+ if (ret != 0)
+ /* XXX: Pages not returned to free list. */
+ return (ret);
+ pagep = *pp;
+ }
+
+ /*
+ * Now, pagep references the page on which to insert and indx is the
+ * the location to insert.
+ */
+ if ((ret = __db_pitem(dbp,
+ pagep, (u_int32_t)*indxp, isize, hdr_dbtp, data_dbtp)) != 0)
+ return (ret);
+
+ (void)memp_fset(dbp->mpf, pagep, DB_MPOOL_DIRTY);
+ return (0);
+}
+
+/*
+ * __db_drem --
+ * Remove a duplicate at the given index on the given page.
+ *
+ * PUBLIC: int __db_drem __P((DB *,
+ * PUBLIC: PAGE **, u_int32_t, int (*)(DB *, PAGE *)));
+ */
+int
+__db_drem(dbp, pp, indx, freefunc)
+ DB *dbp;
+ PAGE **pp;
+ u_int32_t indx;
+ int (*freefunc) __P((DB *, PAGE *));
+{
+ PAGE *pagep;
+ int ret;
+
+ pagep = *pp;
+
+ /* Check if we are freeing a big item. */
+ if (GET_BKEYDATA(pagep, indx)->type == B_OVERFLOW) {
+ if ((ret = __db_doff(dbp,
+ GET_BOVERFLOW(pagep, indx)->pgno, freefunc)) != 0)
+ return (ret);
+ ret = __db_ditem(dbp, pagep, indx, BOVERFLOW_SIZE);
+ } else
+ ret = __db_ditem(dbp, pagep, indx,
+ BKEYDATA_SIZE(GET_BKEYDATA(pagep, indx)->len));
+ if (ret != 0)
+ return (ret);
+
+ if (NUM_ENT(pagep) == 0) {
+ /*
+ * If the page is emptied, then the page is freed and the pp
+ * parameter is set to reference the next, locked page in the
+ * duplicate chain, if one exists. If there was no such page,
+ * then it is set to NULL.
+ *
+ * !!!
+ * __db_relink will set the dirty bit for us.
+ */
+ if ((ret = __db_relink(dbp, pagep, pp, 0)) != 0)
+ return (ret);
+ if ((ret = freefunc(dbp, pagep)) != 0)
+ return (ret);
+ } else
+ (void)memp_fset(dbp->mpf, pagep, DB_MPOOL_DIRTY);
+
+ return (0);
+}
+
+/*
+ * __db_dend --
+ * Find the last page in a set of offpage duplicates.
+ *
+ * PUBLIC: int __db_dend __P((DB *, db_pgno_t, PAGE **));
+ */
+int
+__db_dend(dbp, pgno, pagep)
+ DB *dbp;
+ db_pgno_t pgno;
+ PAGE **pagep;
+{
+ PAGE *h;
+ int ret;
+
+ /*
+ * This implements DB_KEYLAST. The last page is returned in pp; pgno
+ * should be the page number of the first page of the duplicate chain.
+ */
+ for (;;) {
+ if ((ret = memp_fget(dbp->mpf, &pgno, 0, &h)) != 0) {
+ (void)__db_pgerr(dbp, pgno);
+ return (ret);
+ }
+ if ((pgno = NEXT_PGNO(h)) == PGNO_INVALID)
+ break;
+ (void)memp_fput(dbp->mpf, h, 0);
+ }
+
+ *pagep = h;
+ return (0);
+}
+
+/*
+ * __db_dsplit --
+ * Split a page of duplicates, calculating the split point based
+ * on an element of size "size" being added at "*indxp".
+ * On entry hp contains a pointer to the page-pointer of the original
+ * page. On exit, it returns a pointer to the page containing "*indxp"
+ * and "indxp" has been modified to reflect the index on the new page
+ * where the element should be added. The function returns with
+ * the page on which the insert should happen, not yet put.
+ */
+static int
+__db_dsplit(dbp, hp, indxp, size, newfunc)
+ DB *dbp;
+ PAGE **hp;
+ db_indx_t *indxp;
+ u_int32_t size;
+ int (*newfunc) __P((DB *, u_int32_t, PAGE **));
+{
+ PAGE *h, *np, *tp;
+ BKEYDATA *bk;
+ DBT page_dbt;
+ db_indx_t indx, nindex, oindex, sum;
+ db_indx_t halfbytes, i, lastsum;
+ int did_indx, ret, s;
+
+ h = *hp;
+ indx = *indxp;
+
+ /* Create a temporary page to do compaction onto. */
+ if ((tp = (PAGE *)malloc(dbp->pgsize)) == NULL)
+ return (ENOMEM);
+#ifdef DEBUG
+ memset(tp, 0xff, dbp->pgsize);
+#endif
+ /* Create new page for the split. */
+ if ((ret = newfunc(dbp, P_DUPLICATE, &np)) != 0) {
+ FREE(tp, dbp->pgsize);
+ return (ret);
+ }
+
+ P_INIT(np, dbp->pgsize, PGNO(np), PGNO(h), NEXT_PGNO(h), 0,
+ P_DUPLICATE);
+ P_INIT(tp, dbp->pgsize, PGNO(h), PREV_PGNO(h), PGNO(np), 0,
+ P_DUPLICATE);
+
+ /* Figure out the split point */
+ halfbytes = (dbp->pgsize - HOFFSET(h)) / 2;
+ did_indx = 0;
+ for (sum = 0, lastsum = 0, i = 0; i < NUM_ENT(h); i++) {
+ if (i == indx) {
+ sum += size;
+ if (lastsum < halfbytes && sum >= halfbytes) {
+ /* We've crossed the halfway point. */
+ if ((db_indx_t)(halfbytes - lastsum) <
+ (db_indx_t)(sum - halfbytes)) {
+ *hp = np;
+ *indxp = 0;
+ i--;
+ } else
+ *indxp = i;
+ break;
+ }
+ *indxp = i;
+ lastsum = sum;
+ did_indx = 1;
+ }
+ if (GET_BKEYDATA(h, i)->type == B_KEYDATA)
+ sum += BKEYDATA_SIZE(GET_BKEYDATA(h, i)->len);
+ else
+ sum += BOVERFLOW_SIZE;
+
+ if (lastsum < halfbytes && sum >= halfbytes) {
+ /* We've crossed the halfway point. */
+ if ((db_indx_t)(halfbytes - lastsum) <
+ (db_indx_t)(sum - halfbytes))
+ i--;
+ break;
+ }
+ }
+
+ /*
+ * Check if we have set the return values of the index pointer and
+ * page pointer.
+ */
+ if (!did_indx) {
+ *hp = np;
+ *indxp = indx - i - 1;
+ }
+
+ if (DB_LOGGING(dbp)) {
+ page_dbt.size = dbp->pgsize;
+ page_dbt.data = h;
+ if ((ret = __db_split_log(dbp->dbenv->lg_info,
+ dbp->txn, &LSN(h), 0, DB_SPLITOLD, dbp->log_fileid,
+ PGNO(h), &page_dbt, &LSN(h))) != 0) {
+ FREE(tp, dbp->pgsize);
+ return (ret);
+ }
+ LSN(tp) = LSN(h);
+ }
+
+ /*
+ * If it's a btree, adjust the cursors.
+ *
+ * i is the index of the last element to stay on the page.
+ */
+ if (dbp->type == DB_BTREE || dbp->type == DB_RECNO)
+ __bam_ca_split(dbp, PGNO(h), PGNO(h), PGNO(np), i + 1, 0);
+
+ for (nindex = 0, oindex = i + 1; oindex < NUM_ENT(h); oindex++) {
+ bk = GET_BKEYDATA(h, oindex);
+ if (bk->type == B_KEYDATA)
+ s = BKEYDATA_SIZE(bk->len);
+ else
+ s = BOVERFLOW_SIZE;
+
+ np->inp[nindex++] = HOFFSET(np) -= s;
+ memcpy((u_int8_t *)np + HOFFSET(np), bk, s);
+ NUM_ENT(np)++;
+ }
+
+ /*
+ * Now do data compaction by copying the remaining stuff onto the
+ * temporary page and then copying it back to the real page.
+ */
+ for (nindex = 0, oindex = 0; oindex <= i; oindex++) {
+ bk = GET_BKEYDATA(h, oindex);
+ if (bk->type == B_KEYDATA)
+ s = BKEYDATA_SIZE(bk->len);
+ else
+ s = BOVERFLOW_SIZE;
+
+ tp->inp[nindex++] = HOFFSET(tp) -= s;
+ memcpy((u_int8_t *)tp + HOFFSET(tp), bk, s);
+ NUM_ENT(tp)++;
+ }
+
+ /*
+ * This page (the temporary) should be only half full, so we do two
+ * memcpy's, one for the top of the page and one for the bottom of
+ * the page. This way we avoid copying the middle which should be
+ * about half a page.
+ */
+ memcpy(h, tp, LOFFSET(tp));
+ memcpy((u_int8_t *)h + HOFFSET(tp),
+ (u_int8_t *)tp + HOFFSET(tp), dbp->pgsize - HOFFSET(tp));
+ FREE(tp, dbp->pgsize);
+
+ if (DB_LOGGING(dbp)) {
+ page_dbt.size = dbp->pgsize;
+ page_dbt.data = h;
+ if ((ret = __db_split_log(dbp->dbenv->lg_info,
+ dbp->txn, &LSN(h), 0, DB_SPLITNEW, dbp->log_fileid,
+ PGNO(h), &page_dbt, &LSN(h))) != 0)
+ return (ret);
+
+ page_dbt.size = dbp->pgsize;
+ page_dbt.data = np;
+ if ((ret = __db_split_log(dbp->dbenv->lg_info,
+ dbp->txn, &LSN(np), 0, DB_SPLITNEW, dbp->log_fileid,
+ PGNO(np), &page_dbt, &LSN(np))) != 0)
+ return (ret);
+ }
+
+ /*
+ * Figure out if the location we're interested in is on the new
+ * page, and if so, reset the callers' pointer. Push the other
+ * page back to the store.
+ */
+ if (*hp == h)
+ ret = memp_fput(dbp->mpf, np, DB_MPOOL_DIRTY);
+ else
+ ret = memp_fput(dbp->mpf, h, DB_MPOOL_DIRTY);
+
+ return (ret);
+}
+
+/*
+ * __db_ditem --
+ * Remove an item from a page.
+ *
+ * PUBLIC: int __db_ditem __P((DB *, PAGE *, int, u_int32_t));
+ */
+int
+__db_ditem(dbp, pagep, indx, nbytes)
+ DB *dbp;
+ PAGE *pagep;
+ int indx;
+ u_int32_t nbytes;
+{
+ DBT ldbt;
+ db_indx_t cnt, offset;
+ int ret;
+ u_int8_t *from;
+
+ if (DB_LOGGING(dbp)) {
+ ldbt.data = P_ENTRY(pagep, indx);
+ ldbt.size = nbytes;
+ if ((ret = __db_addrem_log(dbp->dbenv->lg_info, dbp->txn,
+ &LSN(pagep), 0, DB_REM_DUP, dbp->log_fileid, PGNO(pagep),
+ (u_int32_t)indx, nbytes, &ldbt, NULL, &LSN(pagep))) != 0)
+ return (ret);
+ }
+
+ /*
+ * If there's only a single item on the page, we don't have to
+ * work hard.
+ */
+ if (NUM_ENT(pagep) == 1) {
+ NUM_ENT(pagep) = 0;
+ HOFFSET(pagep) = dbp->pgsize;
+ return (0);
+ }
+
+ /*
+ * Pack the remaining key/data items at the end of the page. Use
+ * memmove(3), the regions may overlap.
+ */
+ from = (u_int8_t *)pagep + HOFFSET(pagep);
+ memmove(from + nbytes, from, pagep->inp[indx] - HOFFSET(pagep));
+ HOFFSET(pagep) += nbytes;
+
+ /* Adjust the indices' offsets. */
+ offset = pagep->inp[indx];
+ for (cnt = 0; cnt < NUM_ENT(pagep); ++cnt)
+ if (pagep->inp[cnt] < offset)
+ pagep->inp[cnt] += nbytes;
+
+ /* Shift the indices down. */
+ --NUM_ENT(pagep);
+ if (indx != NUM_ENT(pagep))
+ memmove(&pagep->inp[indx], &pagep->inp[indx + 1],
+ sizeof(db_indx_t) * (NUM_ENT(pagep) - indx));
+
+ /* If it's a btree, adjust the cursors. */
+ if (dbp->type == DB_BTREE || dbp->type == DB_RECNO)
+ __bam_ca_di(dbp, PGNO(pagep), indx, -1);
+
+ return (0);
+}
+
+/*
+ * __db_pitem --
+ * Put an item on a page.
+ *
+ * PUBLIC: int __db_pitem
+ * PUBLIC: __P((DB *, PAGE *, u_int32_t, u_int32_t, DBT *, DBT *));
+ */
+int
+__db_pitem(dbp, pagep, indx, nbytes, hdr, data)
+ DB *dbp;
+ PAGE *pagep;
+ u_int32_t indx;
+ u_int32_t nbytes;
+ DBT *hdr, *data;
+{
+ BKEYDATA bk;
+ DBT thdr;
+ int ret;
+ u_int8_t *p;
+
+ /*
+ * Put a single item onto a page. The logic figuring out where to
+ * insert and whether it fits is handled in the caller. All we do
+ * here is manage the page shuffling. We cheat a little bit in that
+ * we don't want to copy the dbt on a normal put twice. If hdr is
+ * NULL, we create a BKEYDATA structure on the page, otherwise, just
+ * copy the caller's information onto the page.
+ *
+ * This routine is also used to put entries onto the page where the
+ * entry is pre-built, e.g., during recovery. In this case, the hdr
+ * will point to the entry, and the data argument will be NULL.
+ *
+ * !!!
+ * There's a tremendous potential for off-by-one errors here, since
+ * the passed in header sizes must be adjusted for the structure's
+ * placeholder for the trailing variable-length data field.
+ */
+ if (DB_LOGGING(dbp))
+ if ((ret = __db_addrem_log(dbp->dbenv->lg_info, dbp->txn,
+ &LSN(pagep), 0, DB_ADD_DUP, dbp->log_fileid, PGNO(pagep),
+ (u_int32_t)indx, nbytes, hdr, data, &LSN(pagep))) != 0)
+ return (ret);
+
+ if (hdr == NULL) {
+ bk.deleted = 0;
+ bk.type = B_KEYDATA;
+ bk.len = data == NULL ? 0 : data->size;
+
+ thdr.data = &bk;
+ thdr.size = SSZA(BKEYDATA, data);
+ hdr = &thdr;
+ }
+
+ /* Adjust the index table, then put the item on the page. */
+ if (indx != NUM_ENT(pagep))
+ memmove(&pagep->inp[indx + 1], &pagep->inp[indx],
+ sizeof(db_indx_t) * (NUM_ENT(pagep) - indx));
+ HOFFSET(pagep) -= nbytes;
+ pagep->inp[indx] = HOFFSET(pagep);
+ ++NUM_ENT(pagep);
+
+ p = P_ENTRY(pagep, indx);
+ memcpy(p, hdr->data, hdr->size);
+ if (data != NULL)
+ memcpy(p + hdr->size, data->data, data->size);
+
+ /* If it's a btree, adjust the cursors. */
+ if (dbp->type == DB_BTREE || dbp->type == DB_RECNO)
+ __bam_ca_di(dbp, PGNO(pagep), indx, 1);
+
+ return (0);
+}
+
+/*
+ * __db_relink --
+ * Relink around a deleted page.
+ *
+ * PUBLIC: int __db_relink __P((DB *, PAGE *, PAGE **, int));
+ */
+int
+__db_relink(dbp, pagep, new_next, needlock)
+ DB *dbp;
+ PAGE *pagep, **new_next;
+ int needlock;
+{
+ PAGE *np, *pp;
+ DB_LOCK npl, ppl;
+ DB_LSN *nlsnp, *plsnp;
+ int ret;
+
+ ret = 0;
+ np = pp = NULL;
+ npl = ppl = LOCK_INVALID;
+ nlsnp = plsnp = NULL;
+
+ /* Retrieve and lock the two pages. */
+ if (pagep->next_pgno != PGNO_INVALID) {
+ if (needlock && (ret = __bam_lget(dbp,
+ 0, pagep->next_pgno, DB_LOCK_WRITE, &npl)) != 0)
+ goto err;
+ if ((ret = memp_fget(dbp->mpf,
+ &pagep->next_pgno, 0, &np)) != 0) {
+ (void)__db_pgerr(dbp, pagep->next_pgno);
+ goto err;
+ }
+ nlsnp = &np->lsn;
+ }
+ if (pagep->prev_pgno != PGNO_INVALID) {
+ if (needlock && (ret = __bam_lget(dbp,
+ 0, pagep->prev_pgno, DB_LOCK_WRITE, &ppl)) != 0)
+ goto err;
+ if ((ret = memp_fget(dbp->mpf,
+ &pagep->prev_pgno, 0, &pp)) != 0) {
+ (void)__db_pgerr(dbp, pagep->next_pgno);
+ goto err;
+ }
+ plsnp = &pp->lsn;
+ }
+
+ /* Log the change. */
+ if (DB_LOGGING(dbp)) {
+ if ((ret = __db_relink_log(dbp->dbenv->lg_info, dbp->txn,
+ &pagep->lsn, 0, dbp->log_fileid, pagep->pgno, &pagep->lsn,
+ pagep->prev_pgno, plsnp, pagep->next_pgno, nlsnp)) != 0)
+ goto err;
+ if (np != NULL)
+ np->lsn = pagep->lsn;
+ if (pp != NULL)
+ pp->lsn = pagep->lsn;
+ }
+
+ /*
+ * Modify and release the two pages.
+ *
+ * !!!
+ * The parameter new_next gets set to the page following the page we
+ * are removing. If there is no following page, then new_next gets
+ * set to NULL.
+ */
+ if (np != NULL) {
+ np->prev_pgno = pagep->prev_pgno;
+ if (new_next == NULL)
+ ret = memp_fput(dbp->mpf, np, DB_MPOOL_DIRTY);
+ else {
+ *new_next = np;
+ ret = memp_fset(dbp->mpf, np, DB_MPOOL_DIRTY);
+ }
+ if (ret != 0)
+ goto err;
+ if (needlock)
+ (void)__bam_lput(dbp, npl);
+ } else if (new_next != NULL)
+ *new_next = NULL;
+
+ if (pp != NULL) {
+ pp->next_pgno = pagep->next_pgno;
+ if ((ret = memp_fput(dbp->mpf, pp, DB_MPOOL_DIRTY)) != 0)
+ goto err;
+ if (needlock)
+ (void)__bam_lput(dbp, ppl);
+ }
+ return (0);
+
+err: if (np != NULL)
+ (void)memp_fput(dbp->mpf, np, 0);
+ if (needlock && npl != LOCK_INVALID)
+ (void)__bam_lput(dbp, npl);
+ if (pp != NULL)
+ (void)memp_fput(dbp->mpf, pp, 0);
+ if (needlock && ppl != LOCK_INVALID)
+ (void)__bam_lput(dbp, ppl);
+ return (ret);
+}
+
+/*
+ * __db_ddup --
+ * Delete an offpage chain of duplicates.
+ *
+ * PUBLIC: int __db_ddup __P((DB *, db_pgno_t, int (*)(DB *, PAGE *)));
+ */
+int
+__db_ddup(dbp, pgno, freefunc)
+ DB *dbp;
+ db_pgno_t pgno;
+ int (*freefunc) __P((DB *, PAGE *));
+{
+ PAGE *pagep;
+ DBT tmp_dbt;
+ int ret;
+
+ do {
+ if ((ret = memp_fget(dbp->mpf, &pgno, 0, &pagep)) != 0) {
+ (void)__db_pgerr(dbp, pgno);
+ return (ret);
+ }
+
+ if (DB_LOGGING(dbp)) {
+ tmp_dbt.data = pagep;
+ tmp_dbt.size = dbp->pgsize;
+ if ((ret = __db_split_log(dbp->dbenv->lg_info, dbp->txn,
+ &LSN(pagep), 0, DB_SPLITOLD, dbp->log_fileid,
+ PGNO(pagep), &tmp_dbt, &LSN(pagep))) != 0)
+ return (ret);
+ }
+ pgno = pagep->next_pgno;
+ if ((ret = freefunc(dbp, pagep)) != 0)
+ return (ret);
+ } while (pgno != PGNO_INVALID);
+
+ return (0);
+}
+
+/*
+ * __db_addpage --
+ * Create a new page and link it onto the next_pgno field of the
+ * current page.
+ */
+static int
+__db_addpage(dbp, hp, indxp, newfunc)
+ DB *dbp;
+ PAGE **hp;
+ db_indx_t *indxp;
+ int (*newfunc) __P((DB *, u_int32_t, PAGE **));
+{
+ PAGE *newpage;
+ int ret;
+
+ if ((ret = newfunc(dbp, P_DUPLICATE, &newpage)) != 0)
+ return (ret);
+
+ if (DB_LOGGING(dbp)) {
+ if ((ret = __db_addpage_log(dbp->dbenv->lg_info,
+ dbp->txn, &LSN(*hp), 0, dbp->log_fileid,
+ PGNO(*hp), &LSN(*hp), PGNO(newpage), &LSN(newpage))) != 0) {
+ return (ret);
+ }
+ LSN(newpage) = LSN(*hp);
+ }
+
+ PREV_PGNO(newpage) = PGNO(*hp);
+ NEXT_PGNO(*hp) = PGNO(newpage);
+
+ if ((ret = memp_fput(dbp->mpf, *hp, DB_MPOOL_DIRTY)) != 0)
+ return (ret);
+ *hp = newpage;
+ *indxp = 0;
+ return (0);
+}
diff --git a/db2/db/db_overflow.c b/db2/db/db_overflow.c
new file mode 100644
index 0000000000..2340e9e358
--- /dev/null
+++ b/db2/db/db_overflow.c
@@ -0,0 +1,383 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1996, 1997
+ * Sleepycat Software. All rights reserved.
+ */
+/*
+ * Copyright (c) 1990, 1993, 1994, 1995, 1996
+ * Keith Bostic. All rights reserved.
+ */
+/*
+ * Copyright (c) 1990, 1993, 1994, 1995
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Olson.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#ifndef lint
+static const char sccsid[] = "@(#)db_overflow.c 10.4 (Sleepycat) 7/2/97";
+#endif /* not lint */
+
+#ifndef NO_SYSTEM_INCLUDES
+#include <sys/types.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#endif
+
+#include "db_int.h"
+#include "db_page.h"
+#include "db_am.h"
+#include "common_ext.h"
+
+/*
+ * Big key/data code.
+ *
+ * Big key and data entries are stored on linked lists of pages. The initial
+ * reference is a structure with the total length of the item and the page
+ * number where it begins. Each entry in the linked list contains a pointer
+ * to the next page of data, and so on.
+ */
+
+/*
+ * __db_goff --
+ * Get an offpage item.
+ *
+ * PUBLIC: int __db_goff __P((DB *, DBT *,
+ * PUBLIC: u_int32_t, db_pgno_t, void **, u_int32_t *));
+ */
+int
+__db_goff(dbp, dbt, tlen, pgno, bpp, bpsz)
+ DB *dbp;
+ DBT *dbt;
+ u_int32_t tlen;
+ db_pgno_t pgno;
+ void **bpp;
+ u_int32_t *bpsz;
+{
+ PAGE *h;
+ db_indx_t bytes;
+ int ret;
+ u_int32_t curoff, needed, start;
+ u_int8_t *p, *src;
+
+ /*
+ * Check if the buffer is big enough; if it is not and we are
+ * allowed to malloc space, then we'll malloc it. If we are
+ * not (DB_DBT_USERMEM), then we'll set the dbt and return
+ * appropriately.
+ */
+ if (F_ISSET(dbt, DB_DBT_PARTIAL)) {
+ start = dbt->doff;
+ needed = dbt->dlen;
+ } else {
+ start = 0;
+ needed = tlen;
+ }
+
+ /*
+ * Allocate any necessary memory.
+ *
+ * XXX: Never allocate 0 bytes;
+ */
+ if (F_ISSET(dbt, DB_DBT_USERMEM)) {
+ if (needed > dbt->ulen) {
+ dbt->size = needed;
+ return (ENOMEM);
+ }
+ } else if (F_ISSET(dbt, DB_DBT_MALLOC)) {
+ dbt->data = dbp->db_malloc == NULL ?
+ (void *)malloc(needed + 1) :
+ (void *)dbp->db_malloc(needed + 1);
+ if (dbt->data == NULL)
+ return (ENOMEM);
+ } else if (*bpsz == 0 || *bpsz < needed) {
+ *bpp = (*bpp == NULL ?
+ (void *)malloc(needed + 1) :
+ (void *)realloc(*bpp, needed + 1));
+ if (*bpp == NULL)
+ return (ENOMEM);
+ *bpsz = needed + 1;
+ dbt->data = *bpp;
+ } else
+ dbt->data = *bpp;
+
+ /*
+ * Step through the linked list of pages, copying the data on each
+ * one into the buffer. Never copy more than the total data length.
+ */
+ dbt->size = needed;
+ for (curoff = 0, p = dbt->data; pgno != P_INVALID && needed > 0;) {
+ if ((ret = memp_fget(dbp->mpf, &pgno, 0, &h)) != 0) {
+ (void)__db_pgerr(dbp, pgno);
+ return (ret);
+ }
+ /* Check if we need any bytes from this page. */
+ if (curoff + OV_LEN(h) >= start) {
+ src = (u_int8_t *)h + P_OVERHEAD;
+ bytes = OV_LEN(h);
+ if (start > curoff) {
+ src += start - curoff;
+ bytes -= start - curoff;
+ }
+ if (bytes > needed)
+ bytes = needed;
+ memcpy(p, src, bytes);
+ p += bytes;
+ needed -= bytes;
+ }
+ curoff += OV_LEN(h);
+ pgno = h->next_pgno;
+ memp_fput(dbp->mpf, h, 0);
+ }
+ return (0);
+}
+
+/*
+ * __db_poff --
+ * Put an offpage item.
+ *
+ * PUBLIC: int __db_poff __P((DB *, const DBT *, db_pgno_t *,
+ * PUBLIC: int (*)(DB *, u_int32_t, PAGE **)));
+ */
+int
+__db_poff(dbp, dbt, pgnop, newfunc)
+ DB *dbp;
+ const DBT *dbt;
+ db_pgno_t *pgnop;
+ int (*newfunc) __P((DB *, u_int32_t, PAGE **));
+{
+ PAGE *pagep, *lastp;
+ DB_LSN new_lsn, null_lsn;
+ DBT tmp_dbt;
+ db_indx_t pagespace;
+ u_int32_t sz;
+ u_int8_t *p;
+ int ret;
+
+ /*
+ * Allocate pages and copy the key/data item into them. Calculate the
+ * number of bytes we get for pages we fill completely with a single
+ * item.
+ */
+ pagespace = P_MAXSPACE(dbp->pgsize);
+
+ lastp = NULL;
+ for (p = dbt->data,
+ sz = dbt->size; sz > 0; p += pagespace, sz -= pagespace) {
+ /*
+ * Reduce pagespace so we terminate the loop correctly and
+ * don't copy too much data.
+ */
+ if (sz < pagespace)
+ pagespace = sz;
+
+ /*
+ * Allocate and initialize a new page and copy all or part of
+ * the item onto the page. If sz is less than pagespace, we
+ * have a partial record.
+ */
+ if ((ret = newfunc(dbp, P_OVERFLOW, &pagep)) != 0)
+ return (ret);
+ if (DB_LOGGING(dbp)) {
+ tmp_dbt.data = p;
+ tmp_dbt.size = pagespace;
+ ZERO_LSN(null_lsn);
+ if ((ret = __db_big_log(dbp->dbenv->lg_info, dbp->txn,
+ &new_lsn, 0, DB_ADD_BIG, dbp->log_fileid,
+ PGNO(pagep), lastp ? PGNO(lastp) : PGNO_INVALID,
+ PGNO_INVALID, &tmp_dbt, &LSN(pagep),
+ lastp == NULL ? &null_lsn : &LSN(lastp),
+ &null_lsn)) != 0)
+ return (ret);
+
+ /* Move lsn onto page. */
+ if (lastp)
+ LSN(lastp) = new_lsn;
+ LSN(pagep) = new_lsn;
+ }
+
+ P_INIT(pagep, dbp->pgsize,
+ PGNO(pagep), PGNO_INVALID, PGNO_INVALID, 0, P_OVERFLOW);
+ OV_LEN(pagep) = pagespace;
+ OV_REF(pagep) = 1;
+ memcpy((u_int8_t *)pagep + P_OVERHEAD, p, pagespace);
+
+ /*
+ * If this is the first entry, update the user's info.
+ * Otherwise, update the entry on the last page filled
+ * in and release that page.
+ */
+ if (lastp == NULL)
+ *pgnop = PGNO(pagep);
+ else {
+ lastp->next_pgno = PGNO(pagep);
+ pagep->prev_pgno = PGNO(lastp);
+ (void)memp_fput(dbp->mpf, lastp, DB_MPOOL_DIRTY);
+ }
+ lastp = pagep;
+ }
+ (void)memp_fput(dbp->mpf, lastp, DB_MPOOL_DIRTY);
+ return (0);
+}
+
+/*
+ * __db_ioff --
+ * Increment the reference count on an overflow page.
+ *
+ * PUBLIC: int __db_ioff __P((DB *, db_pgno_t));
+ */
+int
+__db_ioff(dbp, pgno)
+ DB *dbp;
+ db_pgno_t pgno;
+{
+ PAGE *h;
+ int ret;
+
+ if ((ret = memp_fget(dbp->mpf, &pgno, 0, &h)) != 0) {
+ (void)__db_pgerr(dbp, pgno);
+ return (ret);
+ }
+
+ ++OV_REF(h);
+ if (DB_LOGGING(dbp) && (ret = __db_ovref_log(dbp->dbenv->lg_info,
+ dbp->txn, &LSN(h), 0, dbp->log_fileid, h->pgno, &LSN(h))) != 0)
+ return (ret);
+
+ (void)memp_fput(dbp->mpf, h, DB_MPOOL_DIRTY);
+ return (0);
+}
+
+/*
+ * __db_doff --
+ * Delete an offpage chain of overflow pages.
+ *
+ * PUBLIC: int __db_doff __P((DB *, db_pgno_t, int (*)(DB *, PAGE *)));
+ */
+int
+__db_doff(dbp, pgno, freefunc)
+ DB *dbp;
+ db_pgno_t pgno;
+ int (*freefunc) __P((DB *, PAGE *));
+{
+ PAGE *pagep;
+ DB_LSN null_lsn;
+ DBT tmp_dbt;
+ int ret;
+
+ do {
+ if ((ret = memp_fget(dbp->mpf, &pgno, 0, &pagep)) != 0) {
+ (void)__db_pgerr(dbp, pgno);
+ return (ret);
+ }
+
+ /*
+ * If it's an overflow page and it's referenced by more than
+ * one key/data item, decrement the reference count and return.
+ */
+ if (TYPE(pagep) == P_OVERFLOW && OV_REF(pagep) > 1) {
+ --OV_REF(pagep);
+ (void)memp_fput(dbp->mpf, pagep, DB_MPOOL_DIRTY);
+ return (0);
+ }
+
+ if (DB_LOGGING(dbp)) {
+ tmp_dbt.data = (u_int8_t *)pagep + P_OVERHEAD;
+ tmp_dbt.size = OV_LEN(pagep);
+ ZERO_LSN(null_lsn);
+ if ((ret = __db_big_log(dbp->dbenv->lg_info, dbp->txn,
+ &LSN(pagep), 0, DB_REM_BIG, dbp->log_fileid,
+ PGNO(pagep), PREV_PGNO(pagep), NEXT_PGNO(pagep),
+ &tmp_dbt, &LSN(pagep), &null_lsn, &null_lsn)) != 0)
+ return (ret);
+ }
+ pgno = pagep->next_pgno;
+ if ((ret = freefunc(dbp, pagep)) != 0)
+ return (ret);
+ } while (pgno != PGNO_INVALID);
+
+ return (0);
+}
+
+/*
+ * __db_moff --
+ * Match on overflow pages.
+ *
+ * Given a starting page number and a key, return <0, 0, >0 to indicate if the
+ * key on the page is less than, equal to or greater than the key specified.
+ *
+ * PUBLIC: int __db_moff __P((DB *, const DBT *, db_pgno_t));
+ */
+int
+__db_moff(dbp, dbt, pgno)
+ DB *dbp;
+ const DBT *dbt;
+ db_pgno_t pgno;
+{
+ PAGE *pagep;
+ u_int32_t cmp_bytes, key_left;
+ int ret;
+ u_int8_t *p1, *p2;
+
+ /* While there are both keys to compare. */
+ for (ret = 0, p1 = dbt->data,
+ key_left = dbt->size; key_left > 0 && pgno != PGNO_INVALID;) {
+ if (memp_fget(dbp->mpf, &pgno, 0, &pagep) != 0) {
+ (void)__db_pgerr(dbp, pgno);
+ return (0); /* No system error return. */
+ }
+
+ cmp_bytes = OV_LEN(pagep) < key_left ? OV_LEN(pagep) : key_left;
+ key_left -= cmp_bytes;
+ for (p2 =
+ (u_int8_t *)pagep + P_OVERHEAD; cmp_bytes-- > 0; ++p1, ++p2)
+ if (*p1 != *p2) {
+ ret = (long)*p1 - (long)*p2;
+ break;
+ }
+ pgno = NEXT_PGNO(pagep);
+ (void)memp_fput(dbp->mpf, pagep, 0);
+ if (ret != 0)
+ return (ret);
+ }
+ if (key_left > 0) /* DBT is longer than page key. */
+ return (-1);
+ if (pgno != PGNO_INVALID) /* DBT is shorter than page key. */
+ return (1);
+ return (0);
+}
diff --git a/db2/db/db_pr.c b/db2/db/db_pr.c
new file mode 100644
index 0000000000..c103b10e4f
--- /dev/null
+++ b/db2/db/db_pr.c
@@ -0,0 +1,785 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1996, 1997
+ * Sleepycat Software. All rights reserved.
+ */
+
+#include "config.h"
+
+#ifndef lint
+static const char sccsid[] = "@(#)db_pr.c 10.14 (Sleepycat) 8/17/97";
+#endif /* not lint */
+
+#ifndef NO_SYSTEM_INCLUDES
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <errno.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 "hash.h"
+#include "db_am.h"
+
+static void __db_proff __P((void *));
+static void __db_psize __P((DB_MPOOLFILE *));
+
+/*
+ * __db_loadme --
+ * Force loading of this file.
+ *
+ * PUBLIC: void __db_loadme __P((void));
+ */
+void
+__db_loadme()
+{
+ getpid();
+}
+
+static FILE *set_fp;
+
+/*
+ * 64K is the maximum page size, so by default we check for offsets
+ * larger than that, and, where possible, we refine the test.
+ */
+#define PSIZE_BOUNDARY (64 * 1024 + 1)
+static size_t set_psize = PSIZE_BOUNDARY;
+
+/*
+ * __db_prinit --
+ * Initialize tree printing routines.
+ *
+ * PUBLIC: FILE *__db_prinit __P((FILE *));
+ */
+FILE *
+__db_prinit(fp)
+ FILE *fp;
+{
+ if (set_fp == NULL)
+ set_fp = fp == NULL ? stdout : fp;
+ return (set_fp);
+}
+
+/*
+ * __db_dump --
+ * Dump the tree to a file.
+ *
+ * PUBLIC: int __db_dump __P((DB *, char *, int));
+ */
+int
+__db_dump(dbp, name, all)
+ DB *dbp;
+ char *name;
+ int all;
+{
+ FILE *fp, *save_fp;
+
+ save_fp = NULL; /* XXX: Shut the compiler up. */
+
+ if (set_psize == PSIZE_BOUNDARY)
+ __db_psize(dbp->mpf);
+
+ if (name != NULL) {
+ if ((fp = fopen(name, "w")) == NULL)
+ return (errno);
+ save_fp = set_fp;
+ set_fp = fp;
+ } else
+ fp = __db_prinit(NULL);
+
+ (void)__db_prdb(dbp);
+ if (dbp->type == DB_HASH)
+ (void)__db_prhash(dbp);
+ else
+ (void)__db_prbtree(dbp);
+ fprintf(fp, "%s\n", DB_LINE);
+ __db_prtree(dbp->mpf, all);
+
+ if (name != NULL) {
+ (void)fclose(fp);
+ set_fp = save_fp;
+ }
+ return (0);
+}
+
+/*
+ * __db_prdb --
+ * Print out the DB structure information.
+ *
+ * PUBLIC: int __db_prdb __P((DB *));
+ */
+int
+__db_prdb(dbp)
+ DB *dbp;
+{
+ static const FN fn[] = {
+ { DB_AM_DUP, "duplicates" },
+ { DB_AM_INMEM, "in-memory" },
+ { DB_AM_LOCKING, "locking" },
+ { DB_AM_LOGGING, "logging" },
+ { DB_AM_MLOCAL, "local mpool" },
+ { DB_AM_PGDEF, "default page size" },
+ { DB_AM_RDONLY, "read-only" },
+ { DB_AM_RECOVER, "recover" },
+ { DB_AM_SWAP, "needswap" },
+ { DB_AM_THREAD, "thread" },
+ { DB_BT_RECNUM, "btree:records" },
+ { DB_HS_DIRTYMETA, "hash:dirty-meta" },
+ { DB_RE_DELIMITER, "recno:delimiter" },
+ { DB_RE_FIXEDLEN, "recno:fixed-length" },
+ { DB_RE_PAD, "recno:pad" },
+ { DB_RE_RENUMBER, "recno:renumber" },
+ { DB_RE_SNAPSHOT, "recno:snapshot" },
+ { 0 },
+ };
+ FILE *fp;
+ const char *t;
+
+ fp = __db_prinit(NULL);
+
+ switch (dbp->type) {
+ case DB_BTREE:
+ t = "btree";
+ break;
+ case DB_HASH:
+ t = "hash";
+ break;
+ case DB_RECNO:
+ t = "recno";
+ break;
+ default:
+ t = "UNKNOWN";
+ break;
+ }
+
+ fprintf(fp, "%s ", t);
+ __db_prflags(dbp->flags, fn);
+ fprintf(fp, "\n");
+
+ return (0);
+}
+
+/*
+ * __db_prbtree --
+ * Print out the btree internal information.
+ *
+ * PUBLIC: int __db_prbtree __P((DB *));
+ */
+int
+__db_prbtree(dbp)
+ DB *dbp;
+{
+ static const FN mfn[] = {
+ { BTM_DUP, "duplicates" },
+ { BTM_RECNO, "recno" },
+ { 0 },
+ };
+ BTMETA *mp;
+ BTREE *t;
+ DB_LOCK lock;
+ EPG *sp;
+ FILE *fp;
+ RECNO *rp;
+ db_pgno_t i;
+ int ret;
+
+ t = dbp->internal;
+ fp = __db_prinit(NULL);
+
+ (void)fprintf(fp, "%s\nOn-page metadata:\n", DB_LINE);
+ i = PGNO_METADATA;
+ if ((ret = __bam_lget(dbp, 0, PGNO_METADATA, DB_LOCK_READ, &lock)) != 0)
+ return (ret);
+
+ if ((ret = __bam_pget(dbp, (PAGE **)&mp, &i, 0)) != 0)
+ return (ret);
+
+ (void)fprintf(fp, "magic %#lx\n", (u_long)mp->magic);
+ (void)fprintf(fp, "version %lu\n", (u_long)mp->version);
+ (void)fprintf(fp, "pagesize %lu\n", (u_long)mp->pagesize);
+ (void)fprintf(fp, "maxkey: %lu minkey: %lu\n",
+ (u_long)mp->maxkey, (u_long)mp->minkey);
+ (void)fprintf(fp, "free %lu\n", (u_long)mp->free);
+ (void)fprintf(fp, "flags %lu", (u_long)mp->flags);
+ __db_prflags(mp->flags, mfn);
+ (void)fprintf(fp, "\n");
+ (void)memp_fput(dbp->mpf, mp, 0);
+ (void)__bam_lput(dbp, lock);
+
+ (void)fprintf(fp, "%s\nDB_INFO:\n", DB_LINE);
+ (void)fprintf(fp, "bt_maxkey: %lu bt_minkey: %lu\n",
+ (u_long)t->bt_maxkey, (u_long)t->bt_minkey);
+ (void)fprintf(fp, "bt_compare: %#lx bt_prefix: %#lx\n",
+ (u_long)t->bt_compare, (u_long)t->bt_prefix);
+ if ((rp = t->bt_recno) != NULL) {
+ (void)fprintf(fp,
+ "re_delim: %#lx re_pad: %#lx re_len: %lu re_source: %s\n",
+ (u_long)rp->re_delim, (u_long)rp->re_pad,
+ (u_long)rp->re_len,
+ rp->re_source == NULL ? "" : rp->re_source);
+ (void)fprintf(fp,
+ "cmap: %#lx smap: %#lx emap: %#lx msize: %lu\n",
+ (u_long)rp->re_cmap, (u_long)rp->re_smap,
+ (u_long)rp->re_emap, (u_long)rp->re_msize);
+ }
+ (void)fprintf(fp, "stack:");
+ for (sp = t->bt_stack; sp < t->bt_sp; ++sp)
+ (void)fprintf(fp, " %lu", (u_long)sp->page->pgno);
+ (void)fprintf(fp, "\n");
+ (void)fprintf(fp, "ovflsize: %lu\n", (u_long)t->bt_ovflsize);
+ (void)fflush(fp);
+ return (0);
+}
+
+/*
+ * __db_prhash --
+ * Print out the hash internal information.
+ *
+ * PUBLIC: int __db_prhash __P((DB *));
+ */
+int
+__db_prhash(dbp)
+ DB *dbp;
+{
+ FILE *fp;
+ HTAB *t;
+ int i, put_page, ret;
+ db_pgno_t pgno;
+
+ t = dbp->internal;
+
+ fp = __db_prinit(NULL);
+
+ fprintf(fp, "\thash_accesses %lu\n", (u_long)t->hash_accesses);
+ fprintf(fp, "\thash_collisions %lu\n", (u_long)t->hash_collisions);
+ fprintf(fp, "\thash_expansions %lu\n", (u_long)t->hash_expansions);
+ fprintf(fp, "\thash_overflows %lu\n", (u_long)t->hash_overflows);
+ fprintf(fp, "\thash_bigpages %lu\n", (u_long)t->hash_bigpages);
+ fprintf(fp, "\n");
+
+ if (t->hdr == NULL) {
+ pgno = PGNO_METADATA;
+ if ((ret = memp_fget(dbp->mpf, &pgno, 0, &t->hdr)) != 0)
+ return (ret);
+ put_page = 1;
+ } else
+ put_page = 0;
+
+ fprintf(fp, "\tmagic %#lx\n", (u_long)t->hdr->magic);
+ fprintf(fp, "\tversion %lu\n", (u_long)t->hdr->version);
+ fprintf(fp, "\tpagesize %lu\n", (u_long)t->hdr->pagesize);
+ fprintf(fp, "\tovfl_point %lu\n", (u_long)t->hdr->ovfl_point);
+ fprintf(fp, "\tlast_freed %lu\n", (u_long)t->hdr->last_freed);
+ fprintf(fp, "\tmax_bucket %lu\n", (u_long)t->hdr->max_bucket);
+ fprintf(fp, "\thigh_mask %#lx\n", (u_long)t->hdr->high_mask);
+ fprintf(fp, "\tlow_mask %#lx\n", (u_long)t->hdr->low_mask);
+ fprintf(fp, "\tffactor %lu\n", (u_long)t->hdr->ffactor);
+ fprintf(fp, "\tnelem %lu\n", (u_long)t->hdr->nelem);
+ fprintf(fp, "\th_charkey %#lx\n", (u_long)t->hdr->h_charkey);
+
+ for (i = 0; i < NCACHED; i++)
+ fprintf(fp, "%lu ", (u_long)t->hdr->spares[i]);
+ fprintf(fp, "\n");
+
+ (void)fflush(fp);
+ if (put_page) {
+ (void)memp_fput(dbp->mpf, (PAGE *)t->hdr, 0);
+ t->hdr = NULL;
+ }
+ return (0);
+}
+
+/*
+ * __db_prtree --
+ * Print out the entire tree.
+ *
+ * PUBLIC: int __db_prtree __P((DB_MPOOLFILE *, int));
+ */
+int
+__db_prtree(mpf, all)
+ DB_MPOOLFILE *mpf;
+ int all;
+{
+ PAGE *h;
+ db_pgno_t i;
+ int ret, t_ret;
+
+ if (set_psize == PSIZE_BOUNDARY)
+ __db_psize(mpf);
+
+ ret = 0;
+ for (i = PGNO_ROOT;; ++i) {
+ if ((ret = memp_fget(mpf, &i, 0, &h)) != 0)
+ break;
+ if (TYPE(h) != P_INVALID)
+ if ((t_ret = __db_prpage(h, all)) != 0 && ret == 0)
+ ret = t_ret;
+ (void)memp_fput(mpf, h, 0);
+ }
+ (void)fflush(__db_prinit(NULL));
+ return (ret);
+}
+
+/*
+ * __db_prnpage
+ * -- Print out a specific page.
+ *
+ * PUBLIC: int __db_prnpage __P((DB_MPOOLFILE *, db_pgno_t));
+ */
+int
+__db_prnpage(mpf, pgno)
+ DB_MPOOLFILE *mpf;
+ db_pgno_t pgno;
+{
+ PAGE *h;
+ int ret;
+
+ if (set_psize == PSIZE_BOUNDARY)
+ __db_psize(mpf);
+
+ if ((ret = memp_fget(mpf, &pgno, 0, &h)) != 0)
+ return (ret);
+
+ ret = __db_prpage(h, 1);
+ (void)fflush(__db_prinit(NULL));
+
+ (void)memp_fput(mpf, h, 0);
+ return (ret);
+}
+
+/*
+ * __db_prpage
+ * -- Print out a page.
+ *
+ * PUBLIC: int __db_prpage __P((PAGE *, int));
+ */
+int
+__db_prpage(h, all)
+ PAGE *h;
+ int all;
+{
+ BINTERNAL *bi;
+ BKEYDATA *bk;
+ HKEYDATA *hkd;
+ HOFFPAGE a_hkd;
+ FILE *fp;
+ RINTERNAL *ri;
+ db_indx_t dlen, len, i;
+ db_pgno_t pgno;
+ u_int8_t *p;
+ int deleted, ret;
+ const char *s;
+
+ bi = NULL; /* XXX: Shut the compiler up. */
+ bk = NULL;
+ hkd = NULL;
+ ri = NULL;
+
+ fp = __db_prinit(NULL);
+
+ switch (TYPE(h)) {
+ case P_DUPLICATE:
+ s = "duplicate";
+ break;
+ case P_HASH:
+ s = "hash";
+ break;
+ case P_IBTREE:
+ s = "btree internal";
+ break;
+ case P_INVALID:
+ s = "invalid";
+ break;
+ case P_IRECNO:
+ s = "recno internal";
+ break;
+ case P_LBTREE:
+ s = "btree leaf";
+ break;
+ case P_LRECNO:
+ s = "recno leaf";
+ break;
+ case P_OVERFLOW:
+ s = "overflow";
+ break;
+ default:
+ fprintf(fp, "ILLEGAL PAGE TYPE: page: %lu type: %lu\n",
+ (u_long)h->pgno, (u_long)TYPE(h));
+ return (1);
+ }
+ fprintf(fp, "page %4lu: (%s)\n", (u_long)h->pgno, s);
+ fprintf(fp, " lsn.file: %lu lsn.offset: %lu",
+ (u_long)LSN(h).file, (u_long)LSN(h).offset);
+ if (TYPE(h) == P_IBTREE || TYPE(h) == P_IRECNO ||
+ (TYPE(h) == P_LRECNO && h->pgno == PGNO_ROOT))
+ fprintf(fp, " total records: %4lu", (u_long)RE_NREC(h));
+ fprintf(fp, "\n");
+ if (TYPE(h) == P_LBTREE || TYPE(h) == P_LRECNO)
+ fprintf(fp, " prev: %4lu next: %4lu",
+ (u_long)PREV_PGNO(h), (u_long)NEXT_PGNO(h));
+ if (TYPE(h) == P_IBTREE || TYPE(h) == P_LBTREE)
+ fprintf(fp, " level: %2lu", (u_long)h->level);
+ if (TYPE(h) == P_OVERFLOW) {
+ fprintf(fp, " ref cnt: %4lu ", (u_long)OV_REF(h));
+ __db_pr((u_int8_t *)h + P_OVERHEAD, OV_LEN(h));
+ return (0);
+ }
+ fprintf(fp, " entries: %4lu", (u_long)NUM_ENT(h));
+ fprintf(fp, " offset: %4lu\n", (u_long)HOFFSET(h));
+
+ if (!all || TYPE(h) == P_INVALID)
+ return (0);
+
+ ret = 0;
+ for (i = 0; i < NUM_ENT(h); i++) {
+ if (P_ENTRY(h, i) - (u_int8_t *)h < P_OVERHEAD ||
+ (size_t)(P_ENTRY(h, i) - (u_int8_t *)h) >= set_psize) {
+ fprintf(fp,
+ "ILLEGAL PAGE OFFSET: indx: %lu of %lu\n",
+ (u_long)i, (u_long)h->inp[i]);
+ ret = EINVAL;
+ continue;
+ }
+ deleted = 0;
+ switch (TYPE(h)) {
+ case P_HASH:
+ hkd = GET_HKEYDATA(h, i);
+ break;
+ case P_IBTREE:
+ bi = GET_BINTERNAL(h, i);
+ break;
+ case P_IRECNO:
+ ri = GET_RINTERNAL(h, i);
+ break;
+ case P_LBTREE:
+ bk = GET_BKEYDATA(h, i);
+ deleted = i % 2 == 0 &&
+ GET_BKEYDATA(h, i + O_INDX)->deleted;
+ break;
+ case P_LRECNO:
+ case P_DUPLICATE:
+ bk = GET_BKEYDATA(h, i);
+ deleted = GET_BKEYDATA(h, i)->deleted;
+ break;
+ default:
+ fprintf(fp,
+ "ILLEGAL PAGE ITEM: %lu\n", (u_long)TYPE(h));
+ ret = EINVAL;
+ continue;
+ }
+ fprintf(fp, " %s[%03lu] %4lu ",
+ deleted ? "D" : " ", (u_long)i, (u_long)h->inp[i]);
+ switch (TYPE(h)) {
+ case P_HASH:
+ switch (hkd->type) {
+ case H_OFFDUP:
+ memcpy(&pgno,
+ (u_int8_t *)hkd + SSZ(HOFFDUP, pgno),
+ sizeof(db_pgno_t));
+ fprintf(fp,
+ "%4lu [offpage dups]\n", (u_long)pgno);
+ break;
+ case H_DUPLICATE:
+ /*
+ * If this is the first item on a page, then
+ * we cannot figure out how long it is, so
+ * we only print the first one in the duplicate
+ * set.
+ */
+ if (i != 0)
+ len = LEN_HKEYDATA(h, 0, i);
+ else
+ len = 1;
+
+ fprintf(fp, "Duplicates:\n");
+ for (p = hkd->data; p < hkd->data + len;) {
+ memcpy(&dlen, p, sizeof(db_indx_t));
+ p += sizeof(db_indx_t);
+ fprintf(fp, "\t\t");
+ __db_pr(p, dlen);
+ p += sizeof(db_indx_t) + dlen;
+ }
+ break;
+ case H_KEYDATA:
+ if (i != 0)
+ __db_pr(hkd->data,
+ LEN_HKEYDATA(h, 0, i));
+ else
+ fprintf(fp, "%s\n", hkd->data);
+ break;
+ case H_OFFPAGE:
+ memcpy(&a_hkd, hkd, HOFFPAGE_SIZE);
+ fprintf(fp,
+ "overflow: total len: %4lu page: %4lu\n",
+ (u_long)a_hkd.tlen, (u_long)a_hkd.pgno);
+ break;
+ }
+ break;
+ case P_IBTREE:
+ fprintf(fp, "count: %4lu pgno: %4lu ",
+ (u_long)bi->nrecs, (u_long)bi->pgno);
+ switch (bi->type) {
+ case B_KEYDATA:
+ __db_pr(bi->data, bi->len);
+ break;
+ case B_DUPLICATE:
+ case B_OVERFLOW:
+ __db_proff(bi->data);
+ break;
+ default:
+ fprintf(fp, "ILLEGAL BINTERNAL TYPE: %lu\n",
+ (u_long)bi->type);
+ ret = EINVAL;
+ break;
+ }
+ break;
+ case P_IRECNO:
+ fprintf(fp, "entries %4lu pgno %4lu\n",
+ (u_long)ri->nrecs, (u_long)ri->pgno);
+ break;
+ case P_LBTREE:
+ case P_LRECNO:
+ case P_DUPLICATE:
+ switch (bk->type) {
+ case B_KEYDATA:
+ __db_pr(bk->data, bk->len);
+ break;
+ case B_DUPLICATE:
+ case B_OVERFLOW:
+ __db_proff(bk);
+ break;
+ default:
+ fprintf(fp,
+ "ILLEGAL DUPLICATE/LBTREE/LRECNO TYPE: %lu\n",
+ (u_long)bk->type);
+ ret = EINVAL;
+ break;
+ }
+ break;
+ }
+ }
+ (void)fflush(fp);
+ return (ret);
+}
+
+/*
+ * __db_isbad
+ * -- Decide if a page is corrupted.
+ *
+ * PUBLIC: int __db_isbad __P((PAGE *, int));
+ */
+int
+__db_isbad(h, die)
+ PAGE *h;
+ int die;
+{
+ BINTERNAL *bi;
+ BKEYDATA *bk;
+ HKEYDATA *hkd;
+ FILE *fp;
+ db_indx_t i;
+
+ bi = NULL; /* XXX: Shut the compiler up. */
+ bk = NULL;
+ hkd = NULL;
+
+ fp = __db_prinit(NULL);
+
+ switch (TYPE(h)) {
+ case P_DUPLICATE:
+ case P_HASH:
+ case P_IBTREE:
+ case P_INVALID:
+ case P_IRECNO:
+ case P_LBTREE:
+ case P_LRECNO:
+ case P_OVERFLOW:
+ break;
+ default:
+ fprintf(fp, "ILLEGAL PAGE TYPE: page: %lu type: %lu\n",
+ (u_long)h->pgno, (u_long)TYPE(h));
+ goto bad;
+ }
+
+ for (i = 0; i < NUM_ENT(h); i++) {
+ if (P_ENTRY(h, i) - (u_int8_t *)h < P_OVERHEAD ||
+ (size_t)(P_ENTRY(h, i) - (u_int8_t *)h) >= set_psize) {
+ fprintf(fp,
+ "ILLEGAL PAGE OFFSET: indx: %lu of %lu\n",
+ (u_long)i, (u_long)h->inp[i]);
+ goto bad;
+ }
+ switch (TYPE(h)) {
+ case P_HASH:
+ hkd = GET_HKEYDATA(h, i);
+ if (hkd->type != H_OFFDUP &&
+ hkd->type != H_DUPLICATE &&
+ hkd->type != H_KEYDATA &&
+ hkd->type != H_OFFPAGE) {
+ fprintf(fp, "ILLEGAL HASH TYPE: %lu\n",
+ (u_long)hkd->type);
+ goto bad;
+ }
+ break;
+ case P_IBTREE:
+ bi = GET_BINTERNAL(h, i);
+ if (bi->type != B_KEYDATA &&
+ bi->type != B_DUPLICATE &&
+ bi->type != B_OVERFLOW) {
+ fprintf(fp, "ILLEGAL BINTERNAL TYPE: %lu\n",
+ (u_long)bi->type);
+ goto bad;
+ }
+ break;
+ case P_IRECNO:
+ case P_LBTREE:
+ case P_LRECNO:
+ break;
+ case P_DUPLICATE:
+ bk = GET_BKEYDATA(h, i);
+ if (bk->type != B_KEYDATA &&
+ bk->type != B_DUPLICATE &&
+ bk->type != B_OVERFLOW) {
+ fprintf(fp,
+ "ILLEGAL DUPLICATE/LBTREE/LRECNO TYPE: %lu\n",
+ (u_long)bk->type);
+ goto bad;
+ }
+ break;
+ default:
+ fprintf(fp,
+ "ILLEGAL PAGE ITEM: %lu\n", (u_long)TYPE(h));
+ goto bad;
+ }
+ }
+ return (0);
+
+bad: if (die) {
+ abort();
+ /* NOTREACHED */
+ }
+ return (1);
+}
+
+/*
+ * __db_pr --
+ * Print out a data element.
+ *
+ * PUBLIC: void __db_pr __P((u_int8_t *, u_int32_t));
+ */
+void
+__db_pr(p, len)
+ u_int8_t *p;
+ u_int32_t len;
+{
+ FILE *fp;
+ int i, lastch;
+
+ fp = __db_prinit(NULL);
+
+ fprintf(fp, "len: %3lu", (u_long)len);
+ lastch = '.';
+ if (len != 0) {
+ fprintf(fp, " data: ");
+ for (i = len <= 20 ? len : 20; i > 0; --i, ++p) {
+ lastch = *p;
+ if (isprint(*p) || *p == '\n')
+ fprintf(fp, "%c", *p);
+ else
+ fprintf(fp, "%#x", (u_int)*p);
+ }
+ if (len > 20) {
+ fprintf(fp, "...");
+ lastch = '.';
+ }
+ }
+ if (lastch != '\n')
+ fprintf(fp, "\n");
+}
+
+/*
+ * __db_proff --
+ * Print out an off-page element.
+ */
+static void
+__db_proff(vp)
+ void *vp;
+{
+ FILE *fp;
+ BOVERFLOW *p;
+
+ fp = __db_prinit(NULL);
+
+ p = vp;
+ switch (p->type) {
+ case B_OVERFLOW:
+ fprintf(fp, "overflow: total len: %4lu page: %4lu\n",
+ (u_long)p->tlen, (u_long)p->pgno);
+ break;
+ case B_DUPLICATE:
+ fprintf(fp, "duplicate: page: %4lu\n", (u_long)p->pgno);
+ break;
+ }
+}
+
+/*
+ * __db_prflags --
+ * Print out flags values.
+ *
+ * PUBLIC: void __db_prflags __P((u_int32_t, const FN *));
+ */
+void
+__db_prflags(flags, fn)
+ u_int32_t flags;
+ FN const *fn;
+{
+ FILE *fp;
+ const FN *fnp;
+ int found;
+ const char *sep;
+
+ fp = __db_prinit(NULL);
+
+ sep = " (";
+ for (found = 0, fnp = fn; fnp->mask != 0; ++fnp)
+ if (fnp->mask & flags) {
+ fprintf(fp, "%s%s", sep, fnp->name);
+ sep = ", ";
+ found = 1;
+ }
+ if (found)
+ fprintf(fp, ")");
+}
+
+/*
+ * __db_psize --
+ * Get the page size.
+ */
+static void
+__db_psize(mpf)
+ DB_MPOOLFILE *mpf;
+{
+ BTMETA *mp;
+ db_pgno_t pgno;
+
+ set_psize = PSIZE_BOUNDARY - 1;
+
+ pgno = PGNO_METADATA;
+ if (memp_fget(mpf, &pgno, 0, &mp) != 0)
+ return;
+
+ switch (mp->magic) {
+ case DB_BTREEMAGIC:
+ case DB_HASHMAGIC:
+ set_psize = mp->pagesize;
+ break;
+ }
+ (void)memp_fput(mpf, mp, 0);
+}
diff --git a/db2/db/db_rec.c b/db2/db/db_rec.c
new file mode 100644
index 0000000000..900b0ed579
--- /dev/null
+++ b/db2/db/db_rec.c
@@ -0,0 +1,623 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1996, 1997
+ * Sleepycat Software. All rights reserved.
+ */
+
+#include "config.h"
+
+#ifndef lint
+static const char sccsid[] = "@(#)db_rec.c 10.8 (Sleepycat) 8/22/97";
+#endif /* not lint */
+
+#ifndef NO_SYSTEM_INCLUDES
+#include <sys/types.h>
+
+#endif
+#include <ctype.h>
+#include <errno.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "db_int.h"
+#include "shqueue.h"
+#include "db_page.h"
+#include "db_dispatch.h"
+#include "log.h"
+#include "hash.h"
+#include "btree.h"
+
+/*
+ * PUBLIC: int __db_addrem_recover
+ * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
+ *
+ * This log message is generated whenever we add or remove a duplicate
+ * to/from a duplicate page. On recover, we just do the opposite.
+ */
+int
+__db_addrem_recover(logp, dbtp, lsnp, redo, info)
+ DB_LOG *logp;
+ DBT *dbtp;
+ DB_LSN *lsnp;
+ int redo;
+ void *info;
+{
+ __db_addrem_args *argp;
+ DB *file_dbp, *mdbp;
+ DB_MPOOLFILE *mpf;
+ PAGE *pagep;
+ int change, cmp_n, cmp_p, ret;
+
+ REC_PRINT(__db_addrem_print);
+ REC_INTRO(__db_addrem_read);
+
+ if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
+ if (!redo) {
+ /*
+ * We are undoing and the page doesn't exist. That
+ * is equivalent to having a pagelsn of 0, so we
+ * would not have to undo anything. In this case,
+ * don't bother creating a page.
+ */
+ *lsnp = argp->prev_lsn;
+ ret = 0;
+ goto out;
+ } else
+ if ((ret = memp_fget(mpf,
+ &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0)
+ goto out;
+ }
+
+ cmp_n = log_compare(lsnp, &LSN(pagep));
+ cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
+ change = 0;
+ if ((cmp_p == 0 && redo && argp->opcode == DB_ADD_DUP) ||
+ (cmp_n == 0 && !redo && argp->opcode == DB_REM_DUP)) {
+
+ /* Need to redo an add, or undo a delete. */
+ if ((ret = __db_pitem(file_dbp, pagep, argp->indx, argp->nbytes,
+ argp->hdr.size == 0 ? NULL : &argp->hdr,
+ argp->dbt.size == 0 ? NULL : &argp->dbt)) != 0)
+ goto out;
+
+ change = DB_MPOOL_DIRTY;
+
+ } else if ((cmp_n == 0 && !redo && argp->opcode == DB_ADD_DUP) ||
+ (cmp_p == 0 && redo && argp->opcode == DB_REM_DUP)) {
+ /* Need to undo an add, or redo a delete. */
+ if ((ret = __db_ditem(file_dbp, pagep, argp->indx,
+ argp->nbytes)) != 0)
+ goto out;
+ change = DB_MPOOL_DIRTY;
+ }
+
+ if (change)
+ if (redo)
+ LSN(pagep) = *lsnp;
+ else
+ LSN(pagep) = argp->pagelsn;
+
+ if ((ret = memp_fput(mpf, pagep, change)) == 0)
+ *lsnp = argp->prev_lsn;
+
+out: REC_CLOSE;
+}
+
+/*
+ * PUBLIC: int __db_split_recover __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
+ */
+int
+__db_split_recover(logp, dbtp, lsnp, redo, info)
+ DB_LOG *logp;
+ DBT *dbtp;
+ DB_LSN *lsnp;
+ int redo;
+ void *info;
+{
+ __db_split_args *argp;
+ DB *file_dbp, *mdbp;
+ DB_MPOOLFILE *mpf;
+ PAGE *pagep;
+ int change, cmp_n, cmp_p, ret;
+
+ REC_PRINT(__db_split_print);
+ REC_INTRO(__db_split_read);
+
+ if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
+ if (!redo) {
+ /*
+ * We are undoing and the page doesn't exist. That
+ * is equivalent to having a pagelsn of 0, so we
+ * would not have to undo anything. In this case,
+ * don't bother creating a page.
+ */
+ *lsnp = argp->prev_lsn;
+ ret = 0;
+ goto out;
+ } else
+ if ((ret = memp_fget(mpf,
+ &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0)
+ goto out;
+ }
+
+ /*
+ * There are two types of log messages here, one for the old page
+ * and one for the new pages created. The original image in the
+ * SPLITOLD record is used for undo. The image in the SPLITNEW
+ * is used for redo. We should never have a case where there is
+ * a redo operation and the SPLITOLD record is on disk, but not
+ * the SPLITNEW record. Therefore, we only redo NEW messages
+ * and only undo OLD messages.
+ */
+
+ change = 0;
+ cmp_n = log_compare(lsnp, &LSN(pagep));
+ cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
+ if (cmp_p == 0 && redo) {
+ if (argp->opcode == DB_SPLITNEW) {
+ /* Need to redo the split described. */
+ memcpy(pagep,
+ argp->pageimage.data, argp->pageimage.size);
+ }
+ LSN(pagep) = *lsnp;
+ change = DB_MPOOL_DIRTY;
+ } else if (cmp_n == 0 && !redo) {
+ if (argp->opcode == DB_SPLITOLD) {
+ /* Put back the old image. */
+ memcpy(pagep,
+ argp->pageimage.data, argp->pageimage.size);
+ }
+ LSN(pagep) = argp->pagelsn;
+ change = DB_MPOOL_DIRTY;
+ }
+ if ((ret = memp_fput(mpf, pagep, change)) == 0)
+ *lsnp = argp->prev_lsn;
+
+out: REC_CLOSE;
+}
+
+/*
+ * PUBLIC: int __db_big_recover __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
+ */
+int
+__db_big_recover(logp, dbtp, lsnp, redo, info)
+ DB_LOG *logp;
+ DBT *dbtp;
+ DB_LSN *lsnp;
+ int redo;
+ void *info;
+{
+ __db_big_args *argp;
+ DB *file_dbp, *mdbp;
+ DB_MPOOLFILE *mpf;
+ PAGE *pagep;
+ int change, cmp_n, cmp_p, ret;
+
+ REC_PRINT(__db_big_print);
+ REC_INTRO(__db_big_read);
+
+ if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
+ if (!redo) {
+ /*
+ * We are undoing and the page doesn't exist. That
+ * is equivalent to having a pagelsn of 0, so we
+ * would not have to undo anything. In this case,
+ * don't bother creating a page.
+ */
+ ret = 0;
+ goto ppage;
+ } else
+ if ((ret = memp_fget(mpf,
+ &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0)
+ goto out;
+ }
+
+ /*
+ * There are three pages we need to check. The one on which we are
+ * adding data, the previous one whose next_pointer may have
+ * been updated, and the next one whose prev_pointer may have
+ * been updated.
+ */
+ cmp_n = log_compare(lsnp, &LSN(pagep));
+ cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
+ change = 0;
+ if ((cmp_p == 0 && redo && argp->opcode == DB_ADD_BIG) ||
+ (cmp_n == 0 && !redo && argp->opcode == DB_REM_BIG)) {
+ /* We are either redo-ing an add, or undoing a delete. */
+ P_INIT(pagep, file_dbp->pgsize, argp->pgno, argp->prev_pgno,
+ argp->next_pgno, 0, P_OVERFLOW);
+ OV_LEN(pagep) = argp->dbt.size;
+ OV_REF(pagep) = 1;
+ memcpy((u_int8_t *)pagep + P_OVERHEAD, argp->dbt.data,
+ argp->dbt.size);
+ PREV_PGNO(pagep) = argp->prev_pgno;
+ change = DB_MPOOL_DIRTY;
+ } else if ((cmp_n == 0 && !redo && argp->opcode == DB_ADD_BIG) ||
+ (cmp_p == 0 && redo && argp->opcode == DB_REM_BIG)) {
+ /*
+ * We are either undo-ing an add or redo-ing a delete.
+ * The page is about to be reclaimed in either case, so
+ * there really isn't anything to do here.
+ */
+ change = DB_MPOOL_DIRTY;
+ }
+ if (change)
+ LSN(pagep) = redo ? *lsnp : argp->pagelsn;
+
+ if ((ret = memp_fput(mpf, pagep, change)) != 0)
+ goto out;
+
+ /* Now check the previous page. */
+ppage: if (argp->prev_pgno != PGNO_INVALID) {
+ change = 0;
+ if ((ret = memp_fget(mpf, &argp->prev_pgno, 0, &pagep)) != 0)
+ if (!redo) {
+ /*
+ * We are undoing and the page doesn't exist.
+ * That is equivalent to having a pagelsn of 0,
+ * so we would not have to undo anything. In
+ * this case, don't bother creating a page.
+ */
+ *lsnp = argp->prev_lsn;
+ ret = 0;
+ goto npage;
+ } else
+ if ((ret = memp_fget(mpf, &argp->prev_pgno,
+ DB_MPOOL_CREATE, &pagep)) != 0)
+ goto out;
+
+ cmp_n = log_compare(lsnp, &LSN(pagep));
+ cmp_p = log_compare(&LSN(pagep), &argp->prevlsn);
+
+ if ((cmp_p == 0 && redo && argp->opcode == DB_ADD_BIG) ||
+ (cmp_n == 0 && !redo && argp->opcode == DB_REM_BIG)) {
+ /* Redo add, undo delete. */
+ NEXT_PGNO(pagep) = argp->pgno;
+ change = DB_MPOOL_DIRTY;
+ } else if ((cmp_n == 0 &&
+ !redo && argp->opcode == DB_ADD_BIG) ||
+ (cmp_p == 0 && redo && argp->opcode == DB_REM_BIG)) {
+ /* Redo delete, undo add. */
+ NEXT_PGNO(pagep) = argp->next_pgno;
+ change = DB_MPOOL_DIRTY;
+ }
+ if (change)
+ LSN(pagep) = redo ? *lsnp : argp->prevlsn;
+ if ((ret = memp_fput(mpf, pagep, change)) != 0)
+ goto out;
+ }
+
+ /* Now check the next page. Can only be set on a delete. */
+npage: if (argp->next_pgno != PGNO_INVALID) {
+ change = 0;
+ if ((ret = memp_fget(mpf, &argp->next_pgno, 0, &pagep)) != 0)
+ if (!redo) {
+ /*
+ * We are undoing and the page doesn't exist.
+ * That is equivalent to having a pagelsn of 0,
+ * so we would not have to undo anything. In
+ * this case, don't bother creating a page.
+ */
+ *lsnp = argp->prev_lsn;
+ ret = 0;
+ goto out;
+ } else
+ if ((ret = memp_fget(mpf, &argp->next_pgno,
+ DB_MPOOL_CREATE, &pagep)) != 0)
+ goto out;
+
+ cmp_n = log_compare(lsnp, &LSN(pagep));
+ cmp_p = log_compare(&LSN(pagep), &argp->nextlsn);
+ if (cmp_p == 0 && redo) {
+ PREV_PGNO(pagep) = PGNO_INVALID;
+ change = DB_MPOOL_DIRTY;
+ } else if (cmp_n == 0 && !redo) {
+ PREV_PGNO(pagep) = argp->pgno;
+ change = DB_MPOOL_DIRTY;
+ }
+ if (change)
+ LSN(pagep) = redo ? *lsnp : argp->nextlsn;
+ if ((ret = memp_fput(mpf, pagep, change)) != 0)
+ goto out;
+ }
+
+ *lsnp = argp->prev_lsn;
+
+out: REC_CLOSE;
+}
+
+/*
+ * __db_ovref_recover --
+ * Recovery function for __db_ioff().
+ *
+ * PUBLIC: int __db_ovref_recover __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
+ */
+int
+__db_ovref_recover(logp, dbtp, lsnp, redo, info)
+ DB_LOG *logp;
+ DBT *dbtp;
+ DB_LSN *lsnp;
+ int redo;
+ void *info;
+{
+ __db_ovref_args *argp;
+ DB *file_dbp, *mdbp;
+ DB_MPOOLFILE *mpf;
+ PAGE *pagep;
+ int modified, ret;
+
+ REC_PRINT(__db_ovref_print);
+ REC_INTRO(__db_ovref_read);
+
+ if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
+ (void)__db_pgerr(file_dbp, argp->pgno);
+ goto out;
+ }
+
+ modified = 0;
+ if (log_compare(lsnp, &argp->lsn) == 0 && redo) {
+ /* Need to redo update described. */
+ ++OV_REF(pagep);
+
+ pagep->lsn = *lsnp;
+ modified = 1;
+ } else if (log_compare(lsnp, &LSN(pagep)) == 0 && !redo) {
+ /* Need to undo update described. */
+ --OV_REF(pagep);
+
+ pagep->lsn = argp->lsn;
+ modified = 1;
+ }
+ ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0);
+
+ *lsnp = argp->prev_lsn;
+
+out: REC_CLOSE;
+}
+
+/*
+ * __db_relink_recover --
+ * Recovery function for relink.
+ *
+ * PUBLIC: int __db_relink_recover
+ * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
+ */
+int
+__db_relink_recover(logp, dbtp, lsnp, redo, info)
+ DB_LOG *logp;
+ DBT *dbtp;
+ DB_LSN *lsnp;
+ int redo;
+ void *info;
+{
+ __db_relink_args *argp;
+ DB *file_dbp, *mdbp;
+ DB_MPOOLFILE *mpf;
+ PAGE *pagep;
+ int modified, ret;
+
+ REC_PRINT(__db_relink_print);
+ REC_INTRO(__db_relink_read);
+
+ /*
+ * There are three pages we need to check -- the page, and the
+ * previous and next pages, if they existed.
+ */
+ if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
+ if (redo) {
+ (void)__db_pgerr(file_dbp, argp->pgno);
+ goto out;
+ }
+ goto next;
+ }
+ modified = 0;
+ if (log_compare(lsnp, &argp->lsn) == 0 && redo) {
+ /* Redo the relink. */
+ pagep->lsn = *lsnp;
+ modified = 1;
+ } else if (log_compare(lsnp, &LSN(pagep)) == 0 && !redo) {
+ /* Undo the relink. */
+ pagep->next_pgno = argp->next;
+ pagep->prev_pgno = argp->prev;
+
+ pagep->lsn = argp->lsn;
+ modified = 1;
+ }
+ if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) {
+ (void)__db_panic(file_dbp);
+ goto out;
+ }
+
+next: if ((ret = memp_fget(mpf, &argp->next, 0, &pagep)) != 0) {
+ if (redo) {
+ (void)__db_pgerr(file_dbp, argp->next);
+ goto out;
+ }
+ goto prev;
+ }
+ modified = 0;
+ if (log_compare(lsnp, &argp->lsn_next) == 0 && redo) {
+ /* Redo the relink. */
+ pagep->prev_pgno = argp->prev;
+
+ pagep->lsn = *lsnp;
+ modified = 1;
+ } else if (log_compare(lsnp, &LSN(pagep)) == 0 && !redo) {
+ /* Undo the relink. */
+ pagep->prev_pgno = argp->pgno;
+
+ pagep->lsn = argp->lsn_next;
+ modified = 1;
+ }
+ if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) {
+ (void)__db_panic(file_dbp);
+ goto out;
+ }
+
+prev: if ((ret = memp_fget(mpf, &argp->prev, 0, &pagep)) != 0) {
+ if (redo) {
+ (void)__db_pgerr(file_dbp, argp->prev);
+ goto out;
+ }
+ goto done;
+ }
+ modified = 0;
+ if (log_compare(lsnp, &argp->lsn_prev) == 0 && redo) {
+ /* Redo the relink. */
+ pagep->next_pgno = argp->next;
+
+ pagep->lsn = *lsnp;
+ modified = 1;
+ } else if (log_compare(lsnp, &LSN(pagep)) == 0 && !redo) {
+ /* Undo the relink. */
+ pagep->next_pgno = argp->pgno;
+
+ pagep->lsn = argp->lsn_prev;
+ modified = 1;
+ }
+ if ((ret = memp_fput(mpf, pagep, modified ? DB_MPOOL_DIRTY : 0)) != 0) {
+ (void) __db_panic(file_dbp);
+ goto out;
+ }
+
+done: *lsnp = argp->prev_lsn;
+ ret = 0;
+
+out: REC_CLOSE;
+}
+
+/*
+ * PUBLIC: int __db_addpage_recover
+ * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
+ */
+int
+__db_addpage_recover(logp, dbtp, lsnp, redo, info)
+ DB_LOG *logp;
+ DBT *dbtp;
+ DB_LSN *lsnp;
+ int redo;
+ void *info;
+{
+ __db_addpage_args *argp;
+ DB *file_dbp, *mdbp;
+ DB_MPOOLFILE *mpf;
+ PAGE *pagep;
+ int change, cmp_n, cmp_p, ret;
+
+ REC_PRINT(__db_addpage_print);
+ REC_INTRO(__db_addpage_read);
+
+ /*
+ * We need to check two pages: the old one and the new one onto
+ * which we're going to add duplicates. Do the old one first.
+ */
+ if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0)
+ goto out;
+
+ change = 0;
+ cmp_n = log_compare(lsnp, &LSN(pagep));
+ cmp_p = log_compare(&LSN(pagep), &argp->lsn);
+ if (cmp_p == 0 && redo) {
+ NEXT_PGNO(pagep) = argp->nextpgno;
+
+ LSN(pagep) = *lsnp;
+ change = DB_MPOOL_DIRTY;
+ } else if (cmp_n == 0 && !redo) {
+ NEXT_PGNO(pagep) = PGNO_INVALID;
+
+ LSN(pagep) = argp->lsn;
+ change = DB_MPOOL_DIRTY;
+ }
+ if ((ret = memp_fput(mpf, pagep, change)) != 0)
+ goto out;
+
+ if ((ret = memp_fget(mpf, &argp->nextpgno, 0, &pagep)) != 0)
+ if (!redo) {
+ /*
+ * We are undoing and the page doesn't exist. That
+ * is equivalent to having a pagelsn of 0, so we
+ * would not have to undo anything. In this case,
+ * don't bother creating a page.
+ */
+ ret = 0;
+ goto out;
+ } else
+ if ((ret = memp_fget(mpf,
+ &argp->nextpgno, DB_MPOOL_CREATE, &pagep)) != 0)
+ goto out;
+
+ change = 0;
+ cmp_n = log_compare(lsnp, &LSN(pagep));
+ cmp_p = log_compare(&LSN(pagep), &argp->nextlsn);
+ if (cmp_p == 0 && redo) {
+ PREV_PGNO(pagep) = argp->pgno;
+
+ LSN(pagep) = *lsnp;
+ change = DB_MPOOL_DIRTY;
+ } else if (cmp_n == 0 && !redo) {
+ PREV_PGNO(pagep) = PGNO_INVALID;
+
+ LSN(pagep) = argp->nextlsn;
+ change = DB_MPOOL_DIRTY;
+ }
+ ret = memp_fput(mpf, pagep, change);
+
+out: if (ret == 0)
+ *lsnp = argp->prev_lsn;
+ REC_CLOSE;
+}
+
+/*
+ * __db_debug_recover --
+ * Recovery function for debug.
+ *
+ * PUBLIC: int __db_debug_recover __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
+ */
+int
+__db_debug_recover(logp, dbtp, lsnp, redo, info)
+ DB_LOG *logp;
+ DBT *dbtp;
+ DB_LSN *lsnp;
+ int redo;
+ void *info;
+{
+ __db_debug_args *argp;
+ int ret;
+
+ REC_PRINT(__db_debug_print);
+ REC_NOOP_INTRO(__db_debug_read);
+
+ *lsnp = argp->prev_lsn;
+ ret = 0;
+
+ REC_NOOP_CLOSE;
+}
+
+/*
+ * __db_noop_recover --
+ * Recovery function for noop.
+ *
+ * PUBLIC: int __db_noop_recover
+ * PUBLIC: __P((DB_LOG *, DBT *, DB_LSN *, int, void *));
+ */
+int
+__db_noop_recover(logp, dbtp, lsnp, redo, info)
+ DB_LOG *logp;
+ DBT *dbtp;
+ DB_LSN *lsnp;
+ int redo;
+ void *info;
+{
+ __db_noop_args *argp;
+ int ret;
+
+ REC_PRINT(__db_noop_print);
+ REC_NOOP_INTRO(__db_noop_read);
+
+ *lsnp = argp->prev_lsn;
+ ret = 0;
+
+ REC_NOOP_CLOSE;
+}
diff --git a/db2/db/db_ret.c b/db2/db/db_ret.c
new file mode 100644
index 0000000000..ddeb26eb94
--- /dev/null
+++ b/db2/db/db_ret.c
@@ -0,0 +1,149 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1996, 1997
+ * Sleepycat Software. All rights reserved.
+ */
+
+#include "config.h"
+
+#ifndef lint
+static const char sccsid[] = "@(#)db_ret.c 10.5 (Sleepycat) 7/12/97";
+#endif /* not lint */
+
+#ifndef NO_SYSTEM_INCLUDES
+#include <sys/types.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#endif
+
+#include "db_int.h"
+#include "db_page.h"
+#include "btree.h"
+#include "hash.h"
+#include "db_am.h"
+
+/*
+ * __db_ret --
+ * Build return DBT.
+ *
+ * PUBLIC: int __db_ret __P((DB *,
+ * PUBLIC: PAGE *, u_int32_t, DBT *, void **, u_int32_t *));
+ */
+int
+__db_ret(dbp, h, indx, dbt, memp, memsize)
+ DB *dbp;
+ PAGE *h;
+ u_int32_t indx;
+ DBT *dbt;
+ void **memp;
+ u_int32_t *memsize;
+{
+ BKEYDATA *bk;
+ HOFFPAGE ho;
+ BOVERFLOW *bo;
+ u_int32_t len;
+ void *data, *hk;
+
+ switch (TYPE(h)) {
+ case P_HASH:
+ hk = P_ENTRY(h, indx);
+ if (((HKEYDATA *)hk)->type == H_OFFPAGE) {
+ memcpy(&ho, hk, sizeof(HOFFPAGE));
+ return (__db_goff(dbp, dbt,
+ ho.tlen, ho.pgno, memp, memsize));
+ }
+ len = LEN_HKEYDATA(h, dbp->pgsize, indx);
+ data = ((HKEYDATA *)hk)->data;
+ break;
+ case P_DUPLICATE:
+ case P_LBTREE:
+ case P_LRECNO:
+ bk = GET_BKEYDATA(h, indx);
+ if (bk->type == B_OVERFLOW) {
+ bo = (BOVERFLOW *)bk;
+ return (__db_goff(dbp, dbt,
+ bo->tlen, bo->pgno, memp, memsize));
+ }
+ len = bk->len;
+ data = bk->data;
+ break;
+ default:
+ return (__db_pgfmt(dbp, h->pgno));
+ }
+
+ return (__db_retcopy(dbt, data, len, memp, memsize,
+ F_ISSET(dbt, DB_DBT_INTERNAL) ? NULL : dbp->db_malloc));
+}
+
+/*
+ * __db_retcopy --
+ * Copy the returned data into the user's DBT, handling special flags.
+ *
+ * PUBLIC: int __db_retcopy __P((DBT *,
+ * PUBLIC: void *, u_int32_t, void **, u_int32_t *, void *(*)(size_t)));
+ */
+int
+__db_retcopy(dbt, data, len, memp, memsize, db_malloc)
+ DBT *dbt;
+ void *data;
+ u_int32_t len;
+ void **memp;
+ u_int32_t *memsize;
+ void *(*db_malloc) __P((size_t));
+{
+ /* If returning a partial record, reset the length. */
+ if (F_ISSET(dbt, DB_DBT_PARTIAL)) {
+ data = (u_int8_t *)data + dbt->doff;
+ if (len > dbt->doff) {
+ len -= dbt->doff;
+ if (len > dbt->dlen)
+ len = dbt->dlen;
+ } else
+ len = 0;
+ }
+
+ /*
+ * Return the length of the returned record in the DBT size field.
+ * This satisfies the requirement that if we're using user memory
+ * and insufficient memory was provided, return the amount necessary
+ * in the size field.
+ */
+ dbt->size = len;
+
+ /*
+ * Allocate any necessary memory.
+ *
+ * XXX: Never allocate 0 bytes.
+ */
+ if (F_ISSET(dbt, DB_DBT_MALLOC)) {
+ dbt->data = db_malloc == NULL ?
+ (void *)malloc(len + 1) :
+ (void *)db_malloc(len + 1);
+ if (dbt->data == NULL)
+ return (ENOMEM);
+ } else if (F_ISSET(dbt, DB_DBT_USERMEM)) {
+ if (dbt->ulen < len)
+ return (ENOMEM);
+ } else if (memp == NULL || memsize == NULL) {
+ return (EINVAL);
+ } else {
+ if (*memsize == 0 || *memsize < len) {
+ *memp = *memp == NULL ?
+ (void *)malloc(len + 1) :
+ (void *)realloc(*memp, len + 1);
+ if (*memp == NULL) {
+ *memsize = 0;
+ return (ENOMEM);
+ }
+ *memsize = len + 1;
+ }
+ dbt->data = *memp;
+ }
+
+ memcpy(dbt->data, data, len);
+ return (0);
+}
diff --git a/db2/db/db_thread.c b/db2/db/db_thread.c
new file mode 100644
index 0000000000..e956e809d9
--- /dev/null
+++ b/db2/db/db_thread.c
@@ -0,0 +1,125 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1996, 1997
+ * Sleepycat Software. All rights reserved.
+ */
+
+#include "config.h"
+
+#ifndef lint
+static const char sccsid[] = "@(#)db_thread.c 8.11 (Sleepycat) 8/18/97";
+#endif /* not lint */
+
+#ifndef NO_SYSTEM_INCLUDES
+#include <sys/types.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#endif
+
+#include "db_int.h"
+#include "db_page.h"
+#include "shqueue.h"
+#include "db_am.h"
+
+static int __db_getlockid __P((DB *, DB *));
+
+/*
+ * __db_gethandle --
+ * Called by db access method routines when the DB_THREAD flag is set.
+ * This routine returns a handle, either an existing handle from the
+ * chain of handles, or creating one if necessary.
+ *
+ * PUBLIC: int __db_gethandle __P((DB *, int (*)(DB *, DB *), DB **));
+ */
+int
+__db_gethandle(dbp, am_func, dbpp)
+ DB *dbp, **dbpp;
+ int (*am_func) __P((DB *, DB *));
+{
+ DB *ret_dbp;
+ int ret, t_ret;
+
+ if ((ret = __db_mutex_lock((db_mutex_t *)dbp->mutex, -1,
+ dbp->dbenv == NULL ? NULL : dbp->dbenv->db_yield)) != 0)
+ return (ret);
+
+ if ((ret_dbp = LIST_FIRST(&dbp->handleq)) != NULL)
+ /* Simply take one off the list. */
+ LIST_REMOVE(ret_dbp, links);
+ else {
+ /* Allocate a new handle. */
+ if ((ret_dbp = (DB *)malloc(sizeof(*dbp))) == NULL) {
+ ret = ENOMEM;
+ goto err;
+ }
+ memcpy(ret_dbp, dbp, sizeof(*dbp));
+ ret_dbp->internal = NULL;
+ TAILQ_INIT(&ret_dbp->curs_queue);
+
+ /* Set the locker, the lock structure and the lock DBT. */
+ if ((ret = __db_getlockid(dbp, ret_dbp)) != 0)
+ goto err;
+
+ /* Finally, call the access method specific dup function. */
+ if ((ret = am_func(dbp, ret_dbp)) != 0)
+ goto err;
+ }
+
+ *dbpp = ret_dbp;
+
+ if (0) {
+err: if (ret_dbp != NULL)
+ FREE(ret_dbp, sizeof(*ret_dbp));
+ }
+ if ((t_ret =
+ __db_mutex_unlock((db_mutex_t *)dbp->mutex, -1)) != 0 && ret == 0)
+ ret = t_ret;
+ return (ret);
+}
+
+/*
+ * __db_puthandle --
+ * Return a DB handle to the pool for later use.
+ *
+ * PUBLIC: int __db_puthandle __P((DB *));
+ */
+int
+__db_puthandle(dbp)
+ DB *dbp;
+{
+ DB *master;
+ int ret;
+
+ master = dbp->master;
+ if ((ret = __db_mutex_lock((db_mutex_t *)master->mutex, -1,
+ dbp->dbenv == NULL ? NULL : dbp->dbenv->db_yield)) != 0)
+ return (ret);
+
+ LIST_INSERT_HEAD(&master->handleq, dbp, links);
+
+ return (__db_mutex_unlock((db_mutex_t *)master->mutex, -1));
+}
+
+/*
+ * __db_getlockid --
+ * Create a new locker ID and copy the file lock information from
+ * the old DB into the new one.
+ */
+static int
+__db_getlockid(dbp, new_dbp)
+ DB *dbp, *new_dbp;
+{
+ int ret;
+
+ if (F_ISSET(dbp, DB_AM_LOCKING)) {
+ if ((ret = lock_id(dbp->dbenv->lk_info, &new_dbp->locker)) != 0)
+ return (ret);
+ memcpy(new_dbp->lock.fileid, dbp->lock.fileid, DB_FILE_ID_LEN);
+ new_dbp->lock_dbt.size = sizeof(new_dbp->lock);
+ new_dbp->lock_dbt.data = &new_dbp->lock;
+ }
+ return (0);
+}